Curve Fitting: Add alternate 'refit' method
[blender-staging.git] / source / blender / editors / curve / editcurve.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/curve/editcurve.c
29  *  \ingroup edcurve
30  */
31
32 #include "DNA_key_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_anim_types.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_array_utils.h"
40 #include "BLI_blenlib.h"
41 #include "BLI_math.h"
42 #include "BLI_ghash.h"
43
44 #include "BLT_translation.h"
45
46 #include "BKE_context.h"
47 #include "BKE_curve.h"
48 #include "BKE_depsgraph.h"
49 #include "BKE_displist.h"
50 #include "BKE_fcurve.h"
51 #include "BKE_global.h"
52 #include "BKE_key.h"
53 #include "BKE_library.h"
54 #include "BKE_main.h"
55 #include "BKE_report.h"
56 #include "BKE_animsys.h"
57 #include "BKE_action.h"
58 #include "BKE_modifier.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "ED_keyframes_edit.h"
64 #include "ED_object.h"
65 #include "ED_screen.h"
66 #include "ED_transform.h"
67 #include "ED_transform_snap_object_context.h"
68 #include "ED_types.h"
69 #include "ED_util.h"
70 #include "ED_view3d.h"
71 #include "ED_curve.h"
72
73 #include "curve_intern.h"
74
75 #include "curve_fit_nd.h"
76
77 #include "UI_interface.h"
78 #include "UI_resources.h"
79
80 #include "RNA_access.h"
81 #include "RNA_define.h"
82 #include "RNA_enum_types.h"
83
84 /* Undo stuff */
85 typedef struct {
86         ListBase nubase;
87         int actvert;
88         GHash *undoIndex;
89         ListBase fcurves, drivers;
90         int actnu;
91         int flag;
92 } UndoCurve;
93
94 /* Definitions needed for shape keys */
95 typedef struct {
96         void *orig_cv;
97         int key_index, nu_index, pt_index, vertex_index;
98         bool switched;
99         Nurb *orig_nu;
100 } CVKeyIndex;
101
102 void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus);
103 static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split);
104 static int curve_delete_segments(Object *obedit, const bool split);
105
106 ListBase *object_editcurve_get(Object *ob)
107 {
108         if (ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
109                 Curve *cu = ob->data;
110                 return &cu->editnurb->nurbs;
111         }
112         return NULL;
113 }
114
115 /* ******************* PRINTS ********************* */
116
117 #if 0
118 void printknots(Object *obedit)
119 {
120         ListBase *editnurb = object_editcurve_get(obedit);
121         Nurb *nu;
122         int a, num;
123
124         for (nu = editnurb->first; nu; nu = nu->next) {
125                 if (ED_curve_nurb_select_check(nu) && nu->type == CU_NURBS) {
126                         if (nu->knotsu) {
127                                 num = KNOTSU(nu);
128                                 for (a = 0; a < num; a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
129                         }
130                         if (nu->knotsv) {
131                                 num = KNOTSV(nu);
132                                 for (a = 0; a < num; a++) printf("knotv %d: %f\n", a, nu->knotsv[a]);
133                         }
134                 }
135         }
136 }
137 #endif
138
139 /* ********************* Shape keys *************** */
140
141 static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index, Nurb *orig_nu)
142 {
143         CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), "init_cvKeyIndex");
144
145         cvIndex->orig_cv = cv;
146         cvIndex->key_index = key_index;
147         cvIndex->nu_index = nu_index;
148         cvIndex->pt_index = pt_index;
149         cvIndex->vertex_index = vertex_index;
150         cvIndex->switched = false;
151         cvIndex->orig_nu = orig_nu;
152
153         return cvIndex;
154 }
155
156 static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
157 {
158         Nurb *nu = editnurb->nurbs.first;
159         Nurb *orignu = origBase->first;
160         GHash *gh;
161         BezTriple *bezt, *origbezt;
162         BPoint *bp, *origbp;
163         CVKeyIndex *keyIndex;
164         int a, key_index = 0, nu_index = 0, pt_index = 0, vertex_index = 0;
165
166         if (editnurb->keyindex) return;
167
168         gh = BLI_ghash_ptr_new("editNurb keyIndex");
169
170         while (orignu) {
171                 if (orignu->bezt) {
172                         a = orignu->pntsu;
173                         bezt = nu->bezt;
174                         origbezt = orignu->bezt;
175                         pt_index = 0;
176                         while (a--) {
177                                 keyIndex = init_cvKeyIndex(origbezt, key_index, nu_index, pt_index, vertex_index, orignu);
178                                 BLI_ghash_insert(gh, bezt, keyIndex);
179                                 key_index += 12;
180                                 vertex_index += 3;
181                                 bezt++;
182                                 origbezt++;
183                                 pt_index++;
184                         }
185                 }
186                 else {
187                         a = orignu->pntsu * orignu->pntsv;
188                         bp = nu->bp;
189                         origbp = orignu->bp;
190                         pt_index = 0;
191                         while (a--) {
192                                 keyIndex = init_cvKeyIndex(origbp, key_index, nu_index, pt_index, vertex_index, orignu);
193                                 BLI_ghash_insert(gh, bp, keyIndex);
194                                 key_index += 4;
195                                 bp++;
196                                 origbp++;
197                                 pt_index++;
198                                 vertex_index++;
199                         }
200                 }
201
202                 nu = nu->next;
203                 orignu = orignu->next;
204                 nu_index++;
205         }
206
207         editnurb->keyindex = gh;
208 }
209
210 static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, const void *cv)
211 {
212         return BLI_ghash_lookup(editnurb->keyindex, cv);
213 }
214
215 static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, const void *cv)
216 {
217         return BLI_ghash_popkey(editnurb->keyindex, cv, NULL);
218 }
219
220 static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, const BezTriple *bezt)
221 {
222         CVKeyIndex *index = getCVKeyIndex(editnurb, bezt);
223
224         if (!index) {
225                 return NULL;
226         }
227
228         return (BezTriple *)index->orig_cv;
229 }
230
231 static BPoint *getKeyIndexOrig_bp(EditNurb *editnurb, BPoint *bp)
232 {
233         CVKeyIndex *index = getCVKeyIndex(editnurb, bp);
234
235         if (!index) {
236                 return NULL;
237         }
238
239         return (BPoint *)index->orig_cv;
240 }
241
242 static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
243 {
244         CVKeyIndex *index = getCVKeyIndex(editnurb, cv);
245
246         if (!index) {
247                 return -1;
248         }
249
250         return index->key_index;
251 }
252
253 static void keyIndex_delCV(EditNurb *editnurb, const void *cv)
254 {
255         if (!editnurb->keyindex) {
256                 return;
257         }
258
259         BLI_ghash_remove(editnurb->keyindex, cv, NULL, MEM_freeN);
260 }
261
262 static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
263 {
264         keyIndex_delCV(editnurb, bezt);
265 }
266
267 static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp)
268 {
269         keyIndex_delCV(editnurb, bp);
270 }
271
272 static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
273 {
274         int a;
275
276         if (!editnurb->keyindex) {
277                 return;
278         }
279
280         if (nu->bezt) {
281                 const BezTriple *bezt = nu->bezt;
282                 a = nu->pntsu;
283
284                 while (a--) {
285                         BLI_ghash_remove(editnurb->keyindex, bezt, NULL, MEM_freeN);
286                         bezt++;
287                 }
288         }
289         else {
290                 const BPoint *bp = nu->bp;
291                 a = nu->pntsu * nu->pntsv;
292
293                 while (a--) {
294                         BLI_ghash_remove(editnurb->keyindex, bp, NULL, MEM_freeN);
295                         bp++;
296                 }
297         }
298 }
299
300 static void keyIndex_delNurbList(EditNurb *editnurb, ListBase *nubase)
301 {
302         Nurb *nu = nubase->first;
303
304         while (nu) {
305                 keyIndex_delNurb(editnurb, nu);
306
307                 nu = nu->next;
308         }
309 }
310
311 static void keyIndex_updateCV(EditNurb *editnurb, char *cv,
312                               char *newcv, int count, int size)
313 {
314         int i;
315         CVKeyIndex *index;
316
317         if (editnurb->keyindex == NULL) {
318                 /* No shape keys - updating not needed */
319                 return;
320         }
321
322         for (i = 0; i < count; i++) {
323                 index = popCVKeyIndex(editnurb, cv);
324
325                 if (index) {
326                         BLI_ghash_insert(editnurb->keyindex, newcv, index);
327                 }
328
329                 newcv += size;
330                 cv += size;
331         }
332 }
333
334 static void keyIndex_updateBezt(EditNurb *editnurb, BezTriple *bezt,
335                                 BezTriple *newbezt, int count)
336 {
337         keyIndex_updateCV(editnurb, (char *)bezt, (char *)newbezt, count, sizeof(BezTriple));
338 }
339
340 static void keyIndex_updateBP(EditNurb *editnurb, BPoint *bp,
341                               BPoint *newbp, int count)
342 {
343         keyIndex_updateCV(editnurb, (char *)bp, (char *)newbp, count, sizeof(BPoint));
344 }
345
346 static void keyIndex_updateNurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
347 {
348         if (nu->bezt) {
349                 keyIndex_updateBezt(editnurb, nu->bezt, newnu->bezt, newnu->pntsu);
350         }
351         else {
352                 keyIndex_updateBP(editnurb, nu->bp, newnu->bp, newnu->pntsu * newnu->pntsv);
353         }
354 }
355
356 static void keyIndex_swap(EditNurb *editnurb, void *a, void *b)
357 {
358         CVKeyIndex *index1 = popCVKeyIndex(editnurb, a);
359         CVKeyIndex *index2 = popCVKeyIndex(editnurb, b);
360
361         if (index2) BLI_ghash_insert(editnurb->keyindex, a, index2);
362         if (index1) BLI_ghash_insert(editnurb->keyindex, b, index1);
363 }
364
365 static void keyIndex_switchDirection(EditNurb *editnurb, Nurb *nu)
366 {
367         int a;
368         CVKeyIndex *index1, *index2;
369
370         if (nu->bezt) {
371                 BezTriple *bezt1, *bezt2;
372
373                 a = nu->pntsu;
374
375                 bezt1 = nu->bezt;
376                 bezt2 = bezt1 + (a - 1);
377
378                 if (a & 1) ++a;
379
380                 a /= 2;
381
382                 while (a--) {
383                         index1 = getCVKeyIndex(editnurb, bezt1);
384                         index2 = getCVKeyIndex(editnurb, bezt2);
385
386                         if (index1) index1->switched = !index1->switched;
387
388                         if (bezt1 != bezt2) {
389                                 keyIndex_swap(editnurb, bezt1, bezt2);
390
391                                 if (index2) index2->switched = !index2->switched;
392                         }
393
394                         bezt1++;
395                         bezt2--;
396                 }
397         }
398         else {
399                 BPoint *bp1, *bp2;
400
401                 if (nu->pntsv == 1) {
402                         a = nu->pntsu;
403                         bp1 = nu->bp;
404                         bp2 = bp1 + (a - 1);
405                         a /= 2;
406                         while (bp1 != bp2 && a > 0) {
407                                 index1 = getCVKeyIndex(editnurb, bp1);
408                                 index2 = getCVKeyIndex(editnurb, bp2);
409
410                                 if (index1) index1->switched = !index1->switched;
411
412                                 if (bp1 != bp2) {
413                                         if (index2) index2->switched = !index2->switched;
414
415                                         keyIndex_swap(editnurb, bp1, bp2);
416                                 }
417
418                                 a--;
419                                 bp1++;
420                                 bp2--;
421                         }
422                 }
423                 else {
424                         int b;
425
426                         for (b = 0; b < nu->pntsv; b++) {
427
428                                 bp1 = &nu->bp[b * nu->pntsu];
429                                 a = nu->pntsu;
430                                 bp2 = bp1 + (a - 1);
431                                 a /= 2;
432
433                                 while (bp1 != bp2 && a > 0) {
434                                         index1 = getCVKeyIndex(editnurb, bp1);
435                                         index2 = getCVKeyIndex(editnurb, bp2);
436
437                                         if (index1) index1->switched = !index1->switched;
438
439                                         if (bp1 != bp2) {
440                                                 if (index2) index2->switched = !index2->switched;
441
442                                                 keyIndex_swap(editnurb, bp1, bp2);
443                                         }
444
445                                         a--;
446                                         bp1++;
447                                         bp2--;
448                                 }
449                         }
450
451                 }
452         }
453 }
454
455 static void switch_keys_direction(Curve *cu, Nurb *actnu)
456 {
457         KeyBlock *currkey;
458         EditNurb *editnurb = cu->editnurb;
459         ListBase *nubase = &editnurb->nurbs;
460         Nurb *nu;
461         float *fp;
462         int a;
463
464         currkey = cu->key->block.first;
465         while (currkey) {
466                 fp = currkey->data;
467
468                 nu = nubase->first;
469                 while (nu) {
470                         if (nu->bezt) {
471                                 BezTriple *bezt = nu->bezt;
472                                 a = nu->pntsu;
473                                 if (nu == actnu) {
474                                         while (a--) {
475                                                 if (getKeyIndexOrig_bezt(editnurb, bezt)) {
476                                                         swap_v3_v3(fp, fp + 6);
477                                                         *(fp + 9) = -*(fp + 9);
478                                                         fp += 12;
479                                                 }
480                                                 bezt++;
481                                         }
482                                 }
483                                 else {
484                                         fp += a * 12;
485                                 }
486                         }
487                         else {
488                                 BPoint *bp = nu->bp;
489                                 a = nu->pntsu * nu->pntsv;
490                                 if (nu == actnu) {
491                                         while (a--) {
492                                                 if (getKeyIndexOrig_bp(editnurb, bp)) {
493                                                         *(fp + 3) = -*(fp + 3);
494                                                         fp += 4;
495                                                 }
496                                                 bp++;
497                                         }
498                                 }
499                                 else {
500                                         fp += a * 4;
501                                 }
502                         }
503
504                         nu = nu->next;
505                 }
506
507                 currkey = currkey->next;
508         }
509 }
510
511 static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu)
512 {
513         EditNurb *editnurb = cu->editnurb;
514
515         if (!editnurb->keyindex) {
516                 /* no shape keys - nothing to do */
517                 return;
518         }
519
520         keyIndex_switchDirection(editnurb, nu);
521         if (cu->key)
522                 switch_keys_direction(cu, nu);
523 }
524
525 static GHash *dupli_keyIndexHash(GHash *keyindex)
526 {
527         GHash *gh;
528         GHashIterator gh_iter;
529
530         gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_size(keyindex));
531
532         GHASH_ITER (gh_iter, keyindex) {
533                 void *cv = BLI_ghashIterator_getKey(&gh_iter);
534                 CVKeyIndex *index = BLI_ghashIterator_getValue(&gh_iter);
535                 CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
536
537                 memcpy(newIndex, index, sizeof(CVKeyIndex));
538
539                 BLI_ghash_insert(gh, cv, newIndex);
540         }
541
542         return gh;
543 }
544
545 static void key_to_bezt(float *key, BezTriple *basebezt, BezTriple *bezt)
546 {
547         memcpy(bezt, basebezt, sizeof(BezTriple));
548         memcpy(bezt->vec, key, sizeof(float) * 9);
549         bezt->alfa = key[9];
550 }
551
552 static void bezt_to_key(BezTriple *bezt, float *key)
553 {
554         memcpy(key, bezt->vec, sizeof(float) * 9);
555         key[9] = bezt->alfa;
556 }
557
558 static void calc_keyHandles(ListBase *nurb, float *key)
559 {
560         Nurb *nu;
561         int a;
562         float *fp = key;
563         BezTriple *bezt;
564
565         nu = nurb->first;
566         while (nu) {
567                 if (nu->bezt) {
568                         BezTriple *prevp, *nextp;
569                         BezTriple cur, prev, next;
570                         float *startfp, *prevfp, *nextfp;
571
572                         bezt = nu->bezt;
573                         a = nu->pntsu;
574                         startfp = fp;
575
576                         if (nu->flagu & CU_NURB_CYCLIC) {
577                                 prevp = bezt + (a - 1);
578                                 prevfp = fp + (12 * (a - 1));
579                         }
580                         else {
581                                 prevp = NULL;
582                                 prevfp = NULL;
583                         }
584
585                         nextp = bezt + 1;
586                         nextfp = fp + 12;
587
588                         while (a--) {
589                                 key_to_bezt(fp, bezt, &cur);
590
591                                 if (nextp) key_to_bezt(nextfp, nextp, &next);
592                                 if (prevp) key_to_bezt(prevfp, prevp, &prev);
593
594                                 BKE_nurb_handle_calc(&cur, prevp ? &prev : NULL, nextp ? &next : NULL, 0);
595                                 bezt_to_key(&cur, fp);
596
597                                 prevp = bezt;
598                                 prevfp = fp;
599                                 if (a == 1) {
600                                         if (nu->flagu & CU_NURB_CYCLIC) {
601                                                 nextp = nu->bezt;
602                                                 nextfp = startfp;
603                                         }
604                                         else {
605                                                 nextp = NULL;
606                                                 nextfp = NULL;
607                                         }
608                                 }
609                                 else {
610                                         nextp++;
611                                         nextfp += 12;
612                                 }
613
614                                 bezt++;
615                                 fp += 12;
616                         }
617                 }
618                 else {
619                         a = nu->pntsu * nu->pntsv;
620                         fp += a * 4;
621                 }
622
623                 nu = nu->next;
624         }
625 }
626
627 static void calc_shapeKeys(Object *obedit)
628 {
629         Curve *cu = (Curve *)obedit->data;
630
631         /* are there keys? */
632         if (cu->key) {
633                 int a, i;
634                 EditNurb *editnurb = cu->editnurb;
635                 KeyBlock *currkey;
636                 KeyBlock *actkey = BLI_findlink(&cu->key->block, editnurb->shapenr - 1);
637                 BezTriple *bezt, *oldbezt;
638                 BPoint *bp, *oldbp;
639                 Nurb *nu;
640                 int totvert = BKE_nurbList_verts_count(&editnurb->nurbs);
641
642                 float (*ofs)[3] = NULL;
643                 float *oldkey, *newkey, *ofp;
644
645                 /* editing the base key should update others */
646                 if (cu->key->type == KEY_RELATIVE) {
647                         if (BKE_keyblock_is_basis(cu->key, editnurb->shapenr - 1)) { /* active key is a base */
648                                 int totvec = 0;
649
650                                 /* Calculate needed memory to store offset */
651                                 nu = editnurb->nurbs.first;
652                                 while (nu) {
653                                         if (nu->bezt) {
654                                                 /* Three vects to store handles and one for alfa */
655                                                 totvec += nu->pntsu * 4;
656                                         }
657                                         else {
658                                                 totvec += 2 * nu->pntsu * nu->pntsv;
659                                         }
660
661                                         nu = nu->next;
662                                 }
663
664                                 ofs = MEM_callocN(sizeof(float) * 3 * totvec,  "currkey->data");
665                                 nu = editnurb->nurbs.first;
666                                 i = 0;
667                                 while (nu) {
668                                         if (nu->bezt) {
669                                                 bezt = nu->bezt;
670                                                 a = nu->pntsu;
671                                                 while (a--) {
672                                                         oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
673
674                                                         if (oldbezt) {
675                                                                 int j;
676                                                                 for (j = 0; j < 3; ++j) {
677                                                                         sub_v3_v3v3(ofs[i], bezt->vec[j], oldbezt->vec[j]);
678                                                                         i++;
679                                                                 }
680                                                                 ofs[i++][0] = bezt->alfa - oldbezt->alfa;
681                                                         }
682                                                         else {
683                                                                 i += 4;
684                                                         }
685                                                         bezt++;
686                                                 }
687                                         }
688                                         else {
689                                                 bp = nu->bp;
690                                                 a = nu->pntsu * nu->pntsv;
691                                                 while (a--) {
692                                                         oldbp = getKeyIndexOrig_bp(editnurb, bp);
693                                                         if (oldbp) {
694                                                                 sub_v3_v3v3(ofs[i], bp->vec, oldbp->vec);
695                                                                 ofs[i + 1][0] = bp->alfa - oldbp->alfa;
696                                                         }
697                                                         i += 2;
698                                                         bp++;
699                                                 }
700                                         }
701
702                                         nu = nu->next;
703                                 }
704                         }
705                 }
706
707                 currkey = cu->key->block.first;
708                 while (currkey) {
709                         int apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr - 1 == currkey->relative));
710
711                         float *fp = newkey = MEM_callocN(cu->key->elemsize * totvert,  "currkey->data");
712                         ofp = oldkey = currkey->data;
713
714                         nu = editnurb->nurbs.first;
715                         i = 0;
716                         while (nu) {
717                                 if (currkey == actkey) {
718                                         int restore = actkey != cu->key->refkey;
719
720                                         if (nu->bezt) {
721                                                 bezt = nu->bezt;
722                                                 a = nu->pntsu;
723                                                 while (a--) {
724                                                         int j;
725                                                         oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
726
727                                                         for (j = 0; j < 3; ++j, ++i) {
728                                                                 copy_v3_v3(fp, bezt->vec[j]);
729
730                                                                 if (restore && oldbezt) {
731                                                                         copy_v3_v3(bezt->vec[j], oldbezt->vec[j]);
732                                                                 }
733
734                                                                 fp += 3;
735                                                         }
736                                                         fp[0] = bezt->alfa;
737
738                                                         if (restore && oldbezt) {
739                                                                 bezt->alfa = oldbezt->alfa;
740                                                         }
741
742                                                         fp += 3; ++i; /* alphas */
743                                                         bezt++;
744                                                 }
745                                         }
746                                         else {
747                                                 bp = nu->bp;
748                                                 a = nu->pntsu * nu->pntsv;
749                                                 while (a--) {
750                                                         oldbp = getKeyIndexOrig_bp(editnurb, bp);
751
752                                                         copy_v3_v3(fp, bp->vec);
753
754                                                         fp[3] = bp->alfa;
755
756                                                         if (restore && oldbp) {
757                                                                 copy_v3_v3(bp->vec, oldbp->vec);
758                                                                 bp->alfa = oldbp->alfa;
759                                                         }
760
761                                                         fp += 4;
762                                                         bp++;
763                                                         i += 2;
764                                                 }
765                                         }
766                                 }
767                                 else {
768                                         int index;
769                                         const float *curofp;
770
771                                         if (oldkey) {
772                                                 if (nu->bezt) {
773                                                         bezt = nu->bezt;
774                                                         a = nu->pntsu;
775
776                                                         while (a--) {
777                                                                 index = getKeyIndexOrig_keyIndex(editnurb, bezt);
778                                                                 if (index >= 0) {
779                                                                         int j;
780                                                                         curofp = ofp + index;
781
782                                                                         for (j = 0; j < 3; ++j, ++i) {
783                                                                                 copy_v3_v3(fp, curofp);
784
785                                                                                 if (apply_offset) {
786                                                                                         add_v3_v3(fp, ofs[i]);
787                                                                                 }
788
789                                                                                 fp += 3; curofp += 3;
790                                                                         }
791                                                                         fp[0] = curofp[0];
792
793                                                                         if (apply_offset) {
794                                                                                 /* apply alfa offsets */
795                                                                                 add_v3_v3(fp, ofs[i]);
796                                                                                 i++;
797                                                                         }
798
799                                                                         fp += 3; /* alphas */
800                                                                 }
801                                                                 else {
802                                                                         int j;
803                                                                         for (j = 0; j < 3; ++j, ++i) {
804                                                                                 copy_v3_v3(fp, bezt->vec[j]);
805                                                                                 fp += 3;
806                                                                         }
807                                                                         fp[0] = bezt->alfa;
808
809                                                                         fp += 3; /* alphas */
810                                                                 }
811                                                                 bezt++;
812                                                         }
813                                                 }
814                                                 else {
815                                                         bp = nu->bp;
816                                                         a = nu->pntsu * nu->pntsv;
817                                                         while (a--) {
818                                                                 index = getKeyIndexOrig_keyIndex(editnurb, bp);
819
820                                                                 if (index >= 0) {
821                                                                         curofp = ofp + index;
822                                                                         copy_v3_v3(fp, curofp);
823                                                                         fp[3] = curofp[3];
824
825                                                                         if (apply_offset) {
826                                                                                 add_v3_v3(fp, ofs[i]);
827                                                                                 fp[3] += ofs[i + 1][0];
828                                                                         }
829                                                                 }
830                                                                 else {
831                                                                         copy_v3_v3(fp, bp->vec);
832                                                                         fp[3] = bp->alfa;
833                                                                 }
834
835                                                                 fp += 4;
836                                                                 bp++;
837                                                                 i += 2;
838                                                         }
839                                                 }
840                                         }
841                                 }
842
843                                 nu = nu->next;
844                         }
845
846                         if (apply_offset) {
847                                 /* handles could become malicious after offsets applying */
848                                 calc_keyHandles(&editnurb->nurbs, newkey);
849                         }
850
851                         currkey->totelem = totvert;
852                         if (currkey->data) MEM_freeN(currkey->data);
853                         currkey->data = newkey;
854
855                         currkey = currkey->next;
856                 }
857
858                 if (ofs) MEM_freeN(ofs);
859         }
860 }
861
862 /* ********************* Amimation data *************** */
863
864 static bool curve_is_animated(Curve *cu)
865 {
866         AnimData *ad = BKE_animdata_from_id(&cu->id);
867
868         return ad && (ad->action || ad->drivers.first);
869 }
870
871 static void fcurve_path_rename(AnimData *adt, const char *orig_rna_path, char *rna_path,
872                                ListBase *orig_curves, ListBase *curves)
873 {
874         FCurve *fcu, *nfcu, *nextfcu;
875         int len = strlen(orig_rna_path);
876
877         for (fcu = orig_curves->first; fcu; fcu = nextfcu) {
878                 nextfcu = fcu->next;
879                 if (STREQLEN(fcu->rna_path, orig_rna_path, len)) {
880                         char *spath, *suffix = fcu->rna_path + len;
881                         nfcu = copy_fcurve(fcu);
882                         spath = nfcu->rna_path;
883                         nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix);
884                         BLI_addtail(curves, nfcu);
885
886                         if (fcu->grp) {
887                                 action_groups_remove_channel(adt->action, fcu);
888                                 action_groups_add_channel(adt->action, fcu->grp, nfcu);
889                         }
890                         else if ((adt->action) && (&adt->action->curves == orig_curves))
891                                 BLI_remlink(&adt->action->curves, fcu);
892                         else
893                                 BLI_remlink(&adt->drivers, fcu);
894
895                         free_fcurve(fcu);
896
897                         MEM_freeN(spath);
898                 }
899         }
900 }
901
902 static void fcurve_remove(AnimData *adt, ListBase *orig_curves, FCurve *fcu)
903 {
904         if (orig_curves == &adt->drivers) BLI_remlink(&adt->drivers, fcu);
905         else action_groups_remove_channel(adt->action, fcu);
906
907         free_fcurve(fcu);
908 }
909
910 static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
911 {
912         int nu_index = 0, a, pt_index;
913         EditNurb *editnurb = cu->editnurb;
914         Nurb *nu;
915         CVKeyIndex *keyIndex;
916         char rna_path[64], orig_rna_path[64];
917         AnimData *adt = BKE_animdata_from_id(&cu->id);
918         ListBase curves = {NULL, NULL};
919         FCurve *fcu, *next;
920
921         for (nu = editnurb->nurbs.first, nu_index = 0;  nu != NULL;  nu = nu->next, nu_index++) {
922                 if (nu->bezt) {
923                         BezTriple *bezt = nu->bezt;
924                         a = nu->pntsu;
925                         pt_index = 0;
926
927                         while (a--) {
928                                 keyIndex = getCVKeyIndex(editnurb, bezt);
929                                 if (keyIndex) {
930                                         BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d].bezier_points[%d]", nu_index, pt_index);
931                                         BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d].bezier_points[%d]", keyIndex->nu_index, keyIndex->pt_index);
932
933                                         if (keyIndex->switched) {
934                                                 char handle_path[64], orig_handle_path[64];
935                                                 BLI_snprintf(orig_handle_path, sizeof(orig_rna_path), "%s.handle_left", orig_rna_path);
936                                                 BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_right", rna_path);
937                                                 fcurve_path_rename(adt, orig_handle_path, handle_path, orig_curves, &curves);
938
939                                                 BLI_snprintf(orig_handle_path, sizeof(orig_rna_path), "%s.handle_right", orig_rna_path);
940                                                 BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_left", rna_path);
941                                                 fcurve_path_rename(adt, orig_handle_path, handle_path, orig_curves, &curves);
942                                         }
943
944                                         fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
945
946                                         keyIndex->nu_index = nu_index;
947                                         keyIndex->pt_index = pt_index;
948                                 }
949
950                                 bezt++;
951                                 pt_index++;
952                         }
953                 }
954                 else {
955                         BPoint *bp = nu->bp;
956                         a = nu->pntsu * nu->pntsv;
957                         pt_index = 0;
958
959                         while (a--) {
960                                 keyIndex = getCVKeyIndex(editnurb, bp);
961                                 if (keyIndex) {
962                                         BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d].points[%d]", nu_index, pt_index);
963                                         BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d].points[%d]", keyIndex->nu_index, keyIndex->pt_index);
964                                         fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
965
966                                         keyIndex->nu_index = nu_index;
967                                         keyIndex->pt_index = pt_index;
968                                 }
969
970                                 bp++;
971                                 pt_index++;
972                         }
973                 }
974         }
975
976         /* remove paths for removed control points
977          * need this to make further step with copying non-cv related curves copying
978          * not touching cv's f-curves */
979         for (fcu = orig_curves->first; fcu; fcu = next) {
980                 next = fcu->next;
981
982                 if (STREQLEN(fcu->rna_path, "splines", 7)) {
983                         const char *ch = strchr(fcu->rna_path, '.');
984
985                         if (ch && (STREQLEN(ch, ".bezier_points", 14) || STREQLEN(ch, ".points", 7)))
986                                 fcurve_remove(adt, orig_curves, fcu);
987                 }
988         }
989
990         for (nu = editnurb->nurbs.first, nu_index = 0;  nu != NULL;  nu = nu->next, nu_index++) {
991                 keyIndex = NULL;
992                 if (nu->pntsu) {
993                         if (nu->bezt) keyIndex = getCVKeyIndex(editnurb, &nu->bezt[0]);
994                         else keyIndex = getCVKeyIndex(editnurb, &nu->bp[0]);
995                 }
996
997                 if (keyIndex) {
998                         BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d]", nu_index);
999                         BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d]", keyIndex->nu_index);
1000                         fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1001                 }
1002         }
1003
1004         /* the remainders in orig_curves can be copied back (like follow path) */
1005         /* (if it's not path to spline) */
1006         for (fcu = orig_curves->first; fcu; fcu = next) {
1007                 next = fcu->next;
1008
1009                 if (STREQLEN(fcu->rna_path, "splines", 7)) fcurve_remove(adt, orig_curves, fcu);
1010                 else BLI_addtail(&curves, fcu);
1011         }
1012
1013         *orig_curves = curves;
1014 }
1015
1016 /* return 0 if animation data wasn't changed, 1 otherwise */
1017 int ED_curve_updateAnimPaths(Curve *cu)
1018 {
1019         AnimData *adt = BKE_animdata_from_id(&cu->id);
1020         EditNurb *editnurb = cu->editnurb;
1021
1022         if (!editnurb->keyindex)
1023                 return 0;
1024
1025         if (!curve_is_animated(cu)) return 0;
1026
1027         if (adt->action)
1028                 curve_rename_fcurves(cu, &adt->action->curves);
1029
1030         curve_rename_fcurves(cu, &adt->drivers);
1031
1032         return 1;
1033 }
1034
1035 /* ********************* LOAD and MAKE *************** */
1036
1037 static int *initialize_index_map(Object *obedit, int *r_old_totvert)
1038 {
1039         Curve *curve = (Curve *) obedit->data;
1040         EditNurb *editnurb = curve->editnurb;
1041         Nurb *nu;
1042         CVKeyIndex *keyIndex;
1043         int *old_to_new_map;
1044         int old_totvert, i;
1045         int vertex_index;
1046
1047         for (nu = curve->nurb.first, old_totvert = 0; nu != NULL; nu = nu->next) {
1048                 if (nu->bezt) {
1049                         old_totvert += nu->pntsu * 3;
1050                 }
1051                 else {
1052                         old_totvert += nu->pntsu * nu->pntsv;
1053                 }
1054         }
1055
1056         old_to_new_map = MEM_mallocN(old_totvert * sizeof(int), "curve old to new index map");
1057         for (i = 0; i < old_totvert; i++) {
1058                 old_to_new_map[i] = -1;
1059         }
1060
1061         for (nu = editnurb->nurbs.first, vertex_index = 0;
1062              nu != NULL;
1063              nu = nu->next)
1064         {
1065                 if (nu->bezt) {
1066                         BezTriple *bezt = nu->bezt;
1067                         int a = nu->pntsu;
1068
1069                         while (a--) {
1070                                 keyIndex = getCVKeyIndex(editnurb, bezt);
1071                                 if (keyIndex && keyIndex->vertex_index + 2 < old_totvert) {
1072                                         if (keyIndex->switched) {
1073                                                 old_to_new_map[keyIndex->vertex_index] = vertex_index + 2;
1074                                                 old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
1075                                                 old_to_new_map[keyIndex->vertex_index + 2] = vertex_index;
1076                                         }
1077                                         else {
1078                                                 old_to_new_map[keyIndex->vertex_index] = vertex_index;
1079                                                 old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
1080                                                 old_to_new_map[keyIndex->vertex_index + 2] = vertex_index + 2;
1081                                         }
1082                                 }
1083                                 vertex_index += 3;
1084                                 bezt++;
1085                         }
1086                 }
1087                 else {
1088                         BPoint *bp = nu->bp;
1089                         int a = nu->pntsu * nu->pntsv;
1090
1091                         while (a--) {
1092                                 keyIndex = getCVKeyIndex(editnurb, bp);
1093                                 if (keyIndex) {
1094                                         old_to_new_map[keyIndex->vertex_index] = vertex_index;
1095                                 }
1096                                 vertex_index++;
1097                                 bp++;
1098                         }
1099                 }
1100         }
1101
1102         *r_old_totvert = old_totvert;
1103         return old_to_new_map;
1104 }
1105
1106 static void remap_hooks_and_vertex_parents(Object *obedit)
1107 {
1108         Object *object;
1109         Curve *curve = (Curve *) obedit->data;
1110         EditNurb *editnurb = curve->editnurb;
1111         int *old_to_new_map = NULL;
1112         int old_totvert;
1113
1114         if (editnurb->keyindex == NULL) {
1115                 /* TODO(sergey): Happens when separating curves, this would lead to
1116                  * the wrong indices in the hook modifier, address this together with
1117                  * other indices issues.
1118                  */
1119                 return;
1120         }
1121
1122         for (object = G.main->object.first; object; object = object->id.next) {
1123                 ModifierData *md;
1124                 int index;
1125                 if ((object->parent) &&
1126                     (object->parent->data == curve) &&
1127                     ELEM(object->partype, PARVERT1, PARVERT3))
1128                 {
1129                         if (old_to_new_map == NULL) {
1130                                 old_to_new_map = initialize_index_map(obedit, &old_totvert);
1131                         }
1132
1133                         if (object->par1 < old_totvert) {
1134                                 index = old_to_new_map[object->par1];
1135                                 if (index != -1) {
1136                                         object->par1 = index;
1137                                 }
1138                         }
1139                         if (object->par2 < old_totvert) {
1140                                 index = old_to_new_map[object->par2];
1141                                 if (index != -1) {
1142                                         object->par2 = index;
1143                                 }
1144                         }
1145                         if (object->par3 < old_totvert) {
1146                                 index = old_to_new_map[object->par3];
1147                                 if (index != -1) {
1148                                         object->par3 = index;
1149                                 }
1150                         }
1151                 }
1152                 if (object->data == curve) {
1153                         for (md = object->modifiers.first; md; md = md->next) {
1154                                 if (md->type == eModifierType_Hook) {
1155                                         HookModifierData *hmd = (HookModifierData *) md;
1156                                         int i, j;
1157
1158                                         if (old_to_new_map == NULL) {
1159                                                 old_to_new_map = initialize_index_map(obedit, &old_totvert);
1160                                         }
1161
1162                                         for (i = j = 0; i < hmd->totindex; i++) {
1163                                                 if (hmd->indexar[i] < old_totvert) {
1164                                                         index = old_to_new_map[hmd->indexar[i]];
1165                                                         if (index != -1) {
1166                                                                 hmd->indexar[j++] = index;
1167                                                         }
1168                                                 }
1169                                                 else {
1170                                                         j++;
1171                                                 }
1172                                         }
1173
1174                                         hmd->totindex = j;
1175                                 }
1176                         }
1177                 }
1178         }
1179         if (old_to_new_map != NULL) {
1180                 MEM_freeN(old_to_new_map);
1181         }
1182 }
1183
1184 /* load editNurb in object */
1185 void ED_curve_editnurb_load(Object *obedit)
1186 {
1187         ListBase *editnurb = object_editcurve_get(obedit);
1188
1189         if (obedit == NULL) return;
1190
1191         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1192                 Curve *cu = obedit->data;
1193                 Nurb *nu, *newnu;
1194                 ListBase newnurb = {NULL, NULL}, oldnurb = cu->nurb;
1195
1196                 remap_hooks_and_vertex_parents(obedit);
1197
1198                 for (nu = editnurb->first; nu; nu = nu->next) {
1199                         newnu = BKE_nurb_duplicate(nu);
1200                         BLI_addtail(&newnurb, newnu);
1201
1202                         if (nu->type == CU_NURBS) {
1203                                 BKE_nurb_order_clamp_u(nu);
1204                         }
1205                 }
1206
1207                 cu->nurb = newnurb;
1208
1209                 calc_shapeKeys(obedit);
1210                 ED_curve_updateAnimPaths(obedit->data);
1211
1212                 BKE_nurbList_free(&oldnurb);
1213         }
1214 }
1215
1216 /* make copy in cu->editnurb */
1217 void ED_curve_editnurb_make(Object *obedit)
1218 {
1219         Curve *cu = (Curve *)obedit->data;
1220         EditNurb *editnurb = cu->editnurb;
1221         Nurb *nu, *newnu;
1222         KeyBlock *actkey;
1223
1224         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1225                 actkey = BKE_keyblock_from_object(obedit);
1226
1227                 if (actkey) {
1228                         // XXX strcpy(G.editModeTitleExtra, "(Key) ");
1229                         undo_editmode_clear();
1230                         BKE_keyblock_convert_to_curve(actkey, cu, &cu->nurb);
1231                 }
1232
1233                 if (editnurb) {
1234                         BKE_nurbList_free(&editnurb->nurbs);
1235                         BKE_curve_editNurb_keyIndex_free(editnurb);
1236                         editnurb->keyindex = NULL;
1237                 }
1238                 else {
1239                         editnurb = MEM_callocN(sizeof(EditNurb), "editnurb");
1240                         cu->editnurb = editnurb;
1241                 }
1242
1243                 nu = cu->nurb.first;
1244                 while (nu) {
1245                         newnu = BKE_nurb_duplicate(nu);
1246                         BKE_nurb_test2D(newnu); // after join, or any other creation of curve
1247                         BLI_addtail(&editnurb->nurbs, newnu);
1248                         nu = nu->next;
1249                 }
1250
1251                 if (actkey)
1252                         editnurb->shapenr = obedit->shapenr;
1253
1254                 /* animation could be added in editmode even if there was no animdata in
1255                  * object mode hence we always need CVs index be created */
1256                 init_editNurb_keyIndex(editnurb, &cu->nurb);
1257         }
1258 }
1259
1260 void ED_curve_editnurb_free(Object *obedit)
1261 {
1262         Curve *cu = obedit->data;
1263
1264         BKE_curve_editNurb_free(cu);
1265 }
1266
1267 /******************** separate operator ***********************/
1268
1269 static int separate_exec(bContext *C, wmOperator *op)
1270 {
1271         Main *bmain = CTX_data_main(C);
1272         Scene *scene = CTX_data_scene(C);
1273         Object *oldob, *newob;
1274         Base *oldbase, *newbase;
1275         Curve *oldcu, *newcu;
1276         EditNurb *newedit;
1277         ListBase newnurb = {NULL, NULL};
1278
1279         oldbase = CTX_data_active_base(C);
1280         oldob = oldbase->object;
1281         oldcu = oldob->data;
1282
1283         if (oldcu->key) {
1284                 BKE_report(op->reports, RPT_ERROR, "Cannot separate a curve with vertex keys");
1285                 return OPERATOR_CANCELLED;
1286         }
1287
1288         WM_cursor_wait(1);
1289
1290         /* 1. duplicate geometry and check for valid selection for separate */
1291         adduplicateflagNurb(oldob, &newnurb, SELECT, true);
1292
1293         if (BLI_listbase_is_empty(&newnurb)) {
1294                 WM_cursor_wait(0);
1295                 BKE_report(op->reports, RPT_ERROR, "Cannot separate current selection");
1296                 return OPERATOR_CANCELLED;
1297         }
1298
1299         /* 2. duplicate the object and data */
1300         newbase = ED_object_add_duplicate(bmain, scene, oldbase, 0); /* 0 = fully linked */
1301         DAG_relations_tag_update(bmain);
1302
1303         newob = newbase->object;
1304         newcu = newob->data = BKE_curve_copy(bmain, oldcu);
1305         newcu->editnurb = NULL;
1306         id_us_min(&oldcu->id); /* because new curve is a copy: reduce user count */
1307
1308         /* 3. put new object in editmode, clear it and set separated nurbs */
1309         ED_curve_editnurb_make(newob);
1310         newedit = newcu->editnurb;
1311         BKE_nurbList_free(&newedit->nurbs);
1312         BKE_curve_editNurb_keyIndex_free(newedit);
1313         newedit->keyindex = NULL;
1314         BLI_movelisttolist(&newedit->nurbs, &newnurb);
1315
1316         /* 4. put old object out of editmode and delete separated geometry */
1317         ED_curve_editnurb_load(newob);
1318         ED_curve_editnurb_free(newob);
1319         curve_delete_segments(oldob, true);
1320
1321         DAG_id_tag_update(&oldob->id, OB_RECALC_DATA);  /* this is the original one */
1322         DAG_id_tag_update(&newob->id, OB_RECALC_DATA);  /* this is the separated one */
1323
1324         WM_event_add_notifier(C, NC_GEOM | ND_DATA, oldob->data);
1325         WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob);
1326
1327         WM_cursor_wait(0);
1328
1329         return OPERATOR_FINISHED;
1330 }
1331
1332 void CURVE_OT_separate(wmOperatorType *ot)
1333 {
1334         /* identifiers */
1335         ot->name = "Separate";
1336         ot->idname = "CURVE_OT_separate";
1337         ot->description = "Separate selected points from connected unselected points into a new object";
1338         
1339         /* api callbacks */
1340         ot->invoke = WM_operator_confirm;
1341         ot->exec = separate_exec;
1342         ot->poll = ED_operator_editsurfcurve;
1343         
1344         /* flags */
1345         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1346 }
1347
1348 /******************** split operator ***********************/
1349
1350 static int curve_split_exec(bContext *C, wmOperator *op)
1351 {
1352         Object *obedit = CTX_data_edit_object(C);
1353         ListBase *editnurb = object_editcurve_get(obedit);
1354         ListBase newnurb = {NULL, NULL};
1355
1356         adduplicateflagNurb(obedit, &newnurb, SELECT, true);
1357
1358         if (BLI_listbase_is_empty(&newnurb) == false) {
1359                 Curve *cu = obedit->data;
1360                 const int len_orig = BLI_listbase_count(editnurb);
1361
1362                 curve_delete_segments(obedit, true);
1363                 cu->actnu -= len_orig - BLI_listbase_count(editnurb);
1364                 BLI_movelisttolist(editnurb, &newnurb);
1365
1366                 if (ED_curve_updateAnimPaths(obedit->data))
1367                         WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
1368
1369                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1370                 DAG_id_tag_update(obedit->data, 0);
1371         }
1372         else {
1373                 BKE_report(op->reports, RPT_ERROR, "Cannot split current selection");
1374                 return OPERATOR_CANCELLED;
1375         }
1376
1377         return OPERATOR_FINISHED;
1378 }
1379
1380 void CURVE_OT_split(wmOperatorType *ot)
1381 {
1382         /* identifiers */
1383         ot->name = "Split";
1384         ot->idname = "CURVE_OT_split";
1385         ot->description = "Split off selected points from connected unselected points";
1386
1387         /* api callbacks */
1388         ot->exec = curve_split_exec;
1389         ot->poll = ED_operator_editsurfcurve;
1390
1391         /* flags */
1392         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1393 }
1394
1395 /* ******************* FLAGS ********************* */
1396
1397 static bool isNurbselUV(
1398         const Nurb *nu, int flag,
1399         int *r_u, int *r_v)
1400 {
1401         /* return (u != -1): 1 row in u-direction selected. U has value between 0-pntsv
1402          * return (v != -1): 1 column in v-direction selected. V has value between 0-pntsu
1403          */
1404         BPoint *bp;
1405         int a, b, sel;
1406
1407         *r_u = *r_v = -1;
1408
1409         bp = nu->bp;
1410         for (b = 0; b < nu->pntsv; b++) {
1411                 sel = 0;
1412                 for (a = 0; a < nu->pntsu; a++, bp++) {
1413                         if (bp->f1 & flag) sel++;
1414                 }
1415                 if (sel == nu->pntsu) {
1416                         if (*r_u == -1) *r_u = b;
1417                         else return 0;
1418                 }
1419                 else if (sel > 1) {
1420                         return 0;  /* because sel == 1 is still ok */
1421                 }
1422         }
1423
1424         for (a = 0; a < nu->pntsu; a++) {
1425                 sel = 0;
1426                 bp = &nu->bp[a];
1427                 for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
1428                         if (bp->f1 & flag) sel++;
1429                 }
1430                 if (sel == nu->pntsv) {
1431                         if (*r_v == -1) *r_v = a;
1432                         else return 0;
1433                 }
1434                 else if (sel > 1) {
1435                         return 0;
1436                 }
1437         }
1438
1439         if (*r_u == -1 && *r_v > -1) return 1;
1440         if (*r_v == -1 && *r_u > -1) return 1;
1441         return 0;
1442 }
1443
1444 /* return true if U direction is selected and number of selected columns v */
1445 static bool isNurbselU(Nurb *nu, int *v, int flag)
1446 {
1447         BPoint *bp;
1448         int a, b, sel;
1449
1450         *v = 0;
1451
1452         for (b = 0, bp = nu->bp; b < nu->pntsv; b++) {
1453                 sel = 0;
1454                 for (a = 0; a < nu->pntsu; a++, bp++) {
1455                         if (bp->f1 & flag) sel++;
1456                 }
1457                 if (sel == nu->pntsu) {
1458                         (*v)++;
1459                 }
1460                 else if (sel >= 1) {
1461                         *v = 0;
1462                         return 0;
1463                 }
1464         }
1465
1466         return 1;
1467 }
1468
1469 /* return true if V direction is selected and number of selected rows u */
1470 static bool isNurbselV(Nurb *nu, int *u, int flag)
1471 {
1472         BPoint *bp;
1473         int a, b, sel;
1474
1475         *u = 0;
1476
1477         for (a = 0; a < nu->pntsu; a++) {
1478                 bp = &nu->bp[a];
1479                 sel = 0;
1480                 for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
1481                         if (bp->f1 & flag) sel++;
1482                 }
1483                 if (sel == nu->pntsv) {
1484                         (*u)++;
1485                 }
1486                 else if (sel >= 1) {
1487                         *u = 0;
1488                         return 0;
1489                 }
1490         }
1491
1492         return 1;
1493 }
1494
1495 static void rotateflagNurb(ListBase *editnurb, short flag, const float cent[3], float rotmat[3][3])
1496 {
1497         /* all verts with (flag & 'flag') rotate */
1498         Nurb *nu;
1499         BPoint *bp;
1500         int a;
1501
1502         for (nu = editnurb->first; nu; nu = nu->next) {
1503                 if (nu->type == CU_NURBS) {
1504                         bp = nu->bp;
1505                         a = nu->pntsu * nu->pntsv;
1506
1507                         while (a--) {
1508                                 if (bp->f1 & flag) {
1509                                         sub_v3_v3(bp->vec, cent);
1510                                         mul_m3_v3(rotmat, bp->vec);
1511                                         add_v3_v3(bp->vec, cent);
1512                                 }
1513                                 bp++;
1514                         }
1515                 }
1516         }
1517 }
1518
1519 void ed_editnurb_translate_flag(ListBase *editnurb, short flag, const float vec[3])
1520 {
1521         /* all verts with ('flag' & flag) translate */
1522         Nurb *nu;
1523         BezTriple *bezt;
1524         BPoint *bp;
1525         int a;
1526
1527         for (nu = editnurb->first; nu; nu = nu->next) {
1528                 if (nu->type == CU_BEZIER) {
1529                         a = nu->pntsu;
1530                         bezt = nu->bezt;
1531                         while (a--) {
1532                                 if (bezt->f1 & flag) add_v3_v3(bezt->vec[0], vec);
1533                                 if (bezt->f2 & flag) add_v3_v3(bezt->vec[1], vec);
1534                                 if (bezt->f3 & flag) add_v3_v3(bezt->vec[2], vec);
1535                                 bezt++;
1536                         }
1537                 }
1538                 else {
1539                         a = nu->pntsu * nu->pntsv;
1540                         bp = nu->bp;
1541                         while (a--) {
1542                                 if (bp->f1 & flag) add_v3_v3(bp->vec, vec);
1543                                 bp++;
1544                         }
1545                 }
1546
1547                 BKE_nurb_test2D(nu);
1548         }
1549 }
1550
1551 static void weightflagNurb(ListBase *editnurb, short flag, float w)
1552 {
1553         Nurb *nu;
1554         BPoint *bp;
1555         int a;
1556
1557         for (nu = editnurb->first; nu; nu = nu->next) {
1558                 if (nu->type == CU_NURBS) {
1559                         a = nu->pntsu * nu->pntsv;
1560                         bp = nu->bp;
1561                         while (a--) {
1562                                 if (bp->f1 & flag) {
1563                                         /* a mode used to exist for replace/multiple but is was unused */
1564                                         bp->vec[3] *= w;
1565                                 }
1566                                 bp++;
1567                         }
1568                 }
1569         }
1570 }
1571
1572 static void ed_surf_delete_selected(Object *obedit)
1573 {
1574         Curve *cu = obedit->data;
1575         ListBase *editnurb = object_editcurve_get(obedit);
1576         Nurb *nu, *next;
1577         BPoint *bp, *bpn, *newbp;
1578         int a, b, newu, newv;
1579
1580         BLI_assert(obedit->type == OB_SURF);
1581
1582         nu = editnurb->first;
1583         while (nu) {
1584                 next = nu->next;
1585
1586                 /* is entire nurb selected */
1587                 bp = nu->bp;
1588                 a = nu->pntsu * nu->pntsv;
1589                 while (a) {
1590                         a--;
1591                         if (bp->f1 & SELECT) {
1592                                 /* pass */
1593                         }
1594                         else {
1595                                 break;
1596                         }
1597                         bp++;
1598                 }
1599                 if (a == 0) {
1600                         BLI_remlink(editnurb, nu);
1601                         keyIndex_delNurb(cu->editnurb, nu);
1602                         BKE_nurb_free(nu); nu = NULL;
1603                 }
1604                 else {
1605                         if (isNurbselU(nu, &newv, SELECT)) {
1606                                 /* U direction selected */
1607                                 newv = nu->pntsv - newv;
1608                                 if (newv != nu->pntsv) {
1609                                         /* delete */
1610                                         bp = nu->bp;
1611                                         bpn = newbp = (BPoint *)MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
1612                                         for (b = 0; b < nu->pntsv; b++) {
1613                                                 if ((bp->f1 & SELECT) == 0) {
1614                                                         memcpy(bpn, bp, nu->pntsu * sizeof(BPoint));
1615                                                         keyIndex_updateBP(cu->editnurb, bp, bpn, nu->pntsu);
1616                                                         bpn += nu->pntsu;
1617                                                 }
1618                                                 else {
1619                                                         keyIndex_delBP(cu->editnurb, bp);
1620                                                 }
1621                                                 bp += nu->pntsu;
1622                                         }
1623                                         nu->pntsv = newv;
1624                                         MEM_freeN(nu->bp);
1625                                         nu->bp = newbp;
1626                                         BKE_nurb_order_clamp_v(nu);
1627
1628                                         BKE_nurb_knot_calc_v(nu);
1629                                 }
1630                         }
1631                         else if (isNurbselV(nu, &newu, SELECT)) {
1632                                 /* V direction selected */
1633                                 newu = nu->pntsu - newu;
1634                                 if (newu != nu->pntsu) {
1635                                         /* delete */
1636                                         bp = nu->bp;
1637                                         bpn = newbp = (BPoint *)MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
1638                                         for (b = 0; b < nu->pntsv; b++) {
1639                                                 for (a = 0; a < nu->pntsu; a++, bp++) {
1640                                                         if ((bp->f1 & SELECT) == 0) {
1641                                                                 *bpn = *bp;
1642                                                                 keyIndex_updateBP(cu->editnurb, bp, bpn, 1);
1643                                                                 bpn++;
1644                                                         }
1645                                                         else {
1646                                                                 keyIndex_delBP(cu->editnurb, bp);
1647                                                         }
1648                                                 }
1649                                         }
1650                                         MEM_freeN(nu->bp);
1651                                         nu->bp = newbp;
1652                                         if (newu == 1 && nu->pntsv > 1) {    /* make a U spline */
1653                                                 nu->pntsu = nu->pntsv;
1654                                                 nu->pntsv = 1;
1655                                                 SWAP(short, nu->orderu, nu->orderv);
1656                                                 BKE_nurb_order_clamp_u(nu);
1657                                                 if (nu->knotsv) MEM_freeN(nu->knotsv);
1658                                                 nu->knotsv = NULL;
1659                                         }
1660                                         else {
1661                                                 nu->pntsu = newu;
1662                                                 BKE_nurb_order_clamp_u(nu);
1663                                         }
1664                                         BKE_nurb_knot_calc_u(nu);
1665                                 }
1666                         }
1667                 }
1668                 nu = next;
1669         }
1670 }
1671
1672 static void ed_curve_delete_selected(Object *obedit)
1673 {
1674         Curve *cu = obedit->data;
1675         EditNurb *editnurb = cu->editnurb;
1676         ListBase *nubase = &editnurb->nurbs;
1677         Nurb *nu, *next;
1678         BezTriple *bezt, *bezt1;
1679         BPoint *bp, *bp1;
1680         int a, type, nuindex = 0;
1681
1682         /* first loop, can we remove entire pieces? */
1683         nu = nubase->first;
1684         while (nu) {
1685                 next = nu->next;
1686                 if (nu->type == CU_BEZIER) {
1687                         bezt = nu->bezt;
1688                         a = nu->pntsu;
1689                         if (a) {
1690                                 while (a) {
1691                                         if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
1692                                                 /* pass */
1693                                         }
1694                                         else {
1695                                                 break;
1696                                         }
1697                                         a--;
1698                                         bezt++;
1699                                 }
1700                                 if (a == 0) {
1701                                         if (cu->actnu == nuindex)
1702                                                 cu->actnu = CU_ACT_NONE;
1703
1704                                         BLI_remlink(nubase, nu);
1705                                         keyIndex_delNurb(editnurb, nu);
1706                                         BKE_nurb_free(nu); nu = NULL;
1707                                 }
1708                         }
1709                 }
1710                 else {
1711                         bp = nu->bp;
1712                         a = nu->pntsu * nu->pntsv;
1713                         if (a) {
1714                                 while (a) {
1715                                         if (bp->f1 & SELECT) {
1716                                                 /* pass */
1717                                         }
1718                                         else {
1719                                                 break;
1720                                         }
1721                                         a--;
1722                                         bp++;
1723                                 }
1724                                 if (a == 0) {
1725                                         if (cu->actnu == nuindex)
1726                                                 cu->actnu = CU_ACT_NONE;
1727
1728                                         BLI_remlink(nubase, nu);
1729                                         keyIndex_delNurb(editnurb, nu);
1730                                         BKE_nurb_free(nu); nu = NULL;
1731                                 }
1732                         }
1733                 }
1734
1735                 /* Never allow the order to exceed the number of points
1736                  * - note, this is ok but changes unselected nurbs, disable for now */
1737 #if 0
1738                 if ((nu != NULL) && (nu->type == CU_NURBS)) {
1739                         clamp_nurb_order_u(nu);
1740                 }
1741 #endif
1742                 nu = next;
1743                 nuindex++;
1744         }
1745         /* 2nd loop, delete small pieces: just for curves */
1746         nu = nubase->first;
1747         while (nu) {
1748                 next = nu->next;
1749                 type = 0;
1750                 if (nu->type == CU_BEZIER) {
1751                         bezt = nu->bezt;
1752                         for (a = 0; a < nu->pntsu; a++) {
1753                                 if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
1754                                         memmove(bezt, bezt + 1, (nu->pntsu - a - 1) * sizeof(BezTriple));
1755                                         keyIndex_delBezt(editnurb, bezt);
1756                                         keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu - a - 1);
1757                                         nu->pntsu--;
1758                                         a--;
1759                                         type = 1;
1760                                 }
1761                                 else {
1762                                         bezt++;
1763                                 }
1764                         }
1765                         if (type) {
1766                                 bezt1 = (BezTriple *)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "delNurb");
1767                                 memcpy(bezt1, nu->bezt, (nu->pntsu) * sizeof(BezTriple));
1768                                 keyIndex_updateBezt(editnurb, nu->bezt, bezt1, nu->pntsu);
1769                                 MEM_freeN(nu->bezt);
1770                                 nu->bezt = bezt1;
1771                                 BKE_nurb_handles_calc(nu);
1772                         }
1773                 }
1774                 else if (nu->pntsv == 1) {
1775                         bp = nu->bp;
1776
1777                         for (a = 0; a < nu->pntsu; a++) {
1778                                 if (bp->f1 & SELECT) {
1779                                         memmove(bp, bp + 1, (nu->pntsu - a - 1) * sizeof(BPoint));
1780                                         keyIndex_delBP(editnurb, bp);
1781                                         keyIndex_updateBP(editnurb, bp + 1, bp, nu->pntsu - a - 1);
1782                                         nu->pntsu--;
1783                                         a--;
1784                                         type = 1;
1785                                 }
1786                                 else {
1787                                         bp++;
1788                                 }
1789                         }
1790                         if (type) {
1791                                 bp1 = (BPoint *)MEM_mallocN(nu->pntsu * sizeof(BPoint), "delNurb2");
1792                                 memcpy(bp1, nu->bp, (nu->pntsu) * sizeof(BPoint));
1793                                 keyIndex_updateBP(editnurb, nu->bp, bp1, nu->pntsu);
1794                                 MEM_freeN(nu->bp);
1795                                 nu->bp = bp1;
1796
1797                                 /* Never allow the order to exceed the number of points
1798                                  * - note, this is ok but changes unselected nurbs, disable for now */
1799 #if 0
1800                                 if (nu->type == CU_NURBS) {
1801                                         clamp_nurb_order_u(nu);
1802                                 }
1803 #endif
1804                         }
1805                         BKE_nurb_order_clamp_u(nu);
1806                         BKE_nurb_knot_calc_u(nu);
1807                 }
1808                 nu = next;
1809         }
1810 }
1811
1812 /* only for OB_SURF */
1813 bool ed_editnurb_extrude_flag(EditNurb *editnurb, const short flag)
1814 {
1815         Nurb *nu;
1816         BPoint *bp, *bpn, *newbp;
1817         int a, u, v, len;
1818         bool ok = false;
1819
1820         nu = editnurb->nurbs.first;
1821         while (nu) {
1822
1823                 if (nu->pntsv == 1) {
1824                         bp = nu->bp;
1825                         a = nu->pntsu;
1826                         while (a) {
1827                                 if (bp->f1 & flag) {
1828                                         /* pass */
1829                                 }
1830                                 else {
1831                                         break;
1832                                 }
1833                                 bp++;
1834                                 a--;
1835                         }
1836                         if (a == 0) {
1837                                 ok = true;
1838                                 newbp = (BPoint *)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
1839                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
1840                                 bp = newbp + nu->pntsu;
1841                                 ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu);
1842                                 MEM_freeN(nu->bp);
1843                                 nu->bp = newbp;
1844                                 a = nu->pntsu;
1845                                 while (a--) {
1846                                         select_bpoint(bp, SELECT, flag, HIDDEN);
1847                                         select_bpoint(newbp, DESELECT, flag, HIDDEN);
1848                                         bp++; 
1849                                         newbp++;
1850                                 }
1851
1852                                 nu->pntsv = 2;
1853                                 nu->orderv = 2;
1854                                 BKE_nurb_knot_calc_v(nu);
1855                         }
1856                 }
1857                 else {
1858                         /* which row or column is selected */
1859
1860                         if (isNurbselUV(nu, flag, &u, &v)) {
1861
1862                                 /* deselect all */
1863                                 bp = nu->bp;
1864                                 a = nu->pntsu * nu->pntsv;
1865                                 while (a--) {
1866                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
1867                                         bp++;
1868                                 }
1869
1870                                 if (u == 0 || u == nu->pntsv - 1) {      /* row in u-direction selected */
1871                                         ok = true;
1872                                         newbp = (BPoint *)MEM_mallocN(nu->pntsu * (nu->pntsv + 1) *
1873                                                                       sizeof(BPoint), "extrudeNurb1");
1874                                         if (u == 0) {
1875                                                 len = nu->pntsv * nu->pntsu;
1876                                                 ED_curve_bpcpy(editnurb, newbp + nu->pntsu, nu->bp, len);
1877                                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
1878                                                 bp = newbp;
1879                                         }
1880                                         else {
1881                                                 len = nu->pntsv * nu->pntsu;
1882                                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, len);
1883                                                 ED_curve_bpcpy(editnurb, newbp + len, &nu->bp[len - nu->pntsu], nu->pntsu);
1884                                                 bp = newbp + len;
1885                                         }
1886
1887                                         a = nu->pntsu;
1888                                         while (a--) {
1889                                                 select_bpoint(bp, SELECT, flag, HIDDEN);
1890                                                 bp++;
1891                                         }
1892
1893                                         MEM_freeN(nu->bp);
1894                                         nu->bp = newbp;
1895                                         nu->pntsv++;
1896                                         BKE_nurb_knot_calc_v(nu);
1897                                 }
1898                                 else if (v == 0 || v == nu->pntsu - 1) {     /* column in v-direction selected */
1899                                         ok = true;
1900                                         bpn = newbp = (BPoint *)MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
1901                                         bp = nu->bp;
1902
1903                                         for (a = 0; a < nu->pntsv; a++) {
1904                                                 if (v == 0) {
1905                                                         *bpn = *bp;
1906                                                         bpn->f1 |= flag;
1907                                                         bpn++;
1908                                                 }
1909                                                 ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu);
1910                                                 bp += nu->pntsu;
1911                                                 bpn += nu->pntsu;
1912                                                 if (v == nu->pntsu - 1) {
1913                                                         *bpn = *(bp - 1);
1914                                                         bpn->f1 |= flag;
1915                                                         bpn++;
1916                                                 }
1917                                         }
1918
1919                                         MEM_freeN(nu->bp);
1920                                         nu->bp = newbp;
1921                                         nu->pntsu++;
1922                                         BKE_nurb_knot_calc_u(nu);
1923                                 }
1924                         }
1925                 }
1926                 nu = nu->next;
1927         }
1928
1929         return ok;
1930 }
1931
1932 static bool calc_duplicate_actvert(
1933         const ListBase *editnurb, const ListBase *newnurb, Curve *cu,
1934         int start, int end, int vert)
1935 {
1936         if ((start <= cu->actvert) && (end > cu->actvert)) {
1937                 cu->actvert = vert;
1938                 cu->actnu = BLI_listbase_count(editnurb) + BLI_listbase_count(newnurb);
1939                 return true;
1940         }
1941         return false;
1942 }
1943
1944 static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
1945                                 const short flag, const bool split)
1946 {
1947         ListBase *editnurb = object_editcurve_get(obedit);
1948         Nurb *nu, *newnu;
1949         BezTriple *bezt, *bezt1;
1950         BPoint *bp, *bp1, *bp2, *bp3;
1951         Curve *cu = (Curve *)obedit->data;
1952         int a, b, c, starta, enda, diffa, cyclicu, cyclicv, newu, newv, i;
1953         char *usel;
1954
1955         for (i = 0, nu = editnurb->first; nu; i++, nu = nu->next) {
1956                 cyclicu = cyclicv = 0;
1957                 if (nu->type == CU_BEZIER) {
1958                         for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
1959                                 enda = -1;
1960                                 starta = a;
1961                                 while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) {
1962                                         if (!split) select_beztriple(bezt, DESELECT, flag, HIDDEN);
1963                                         enda = a;
1964                                         if (a >= nu->pntsu - 1) break;
1965                                         a++;
1966                                         bezt++;
1967                                 }
1968                                 if (enda >= starta) {
1969                                         newu = diffa = enda - starta + 1; /* set newu and diffa, may use both */
1970
1971                                         if (starta == 0 && newu != nu->pntsu && (nu->flagu & CU_NURB_CYCLIC)) {
1972                                                 cyclicu = newu;
1973                                         }
1974                                         else {
1975                                                 if (enda == nu->pntsu - 1) newu += cyclicu;
1976                                                 if (i == cu->actnu) {
1977                                                         calc_duplicate_actvert(
1978                                                                 editnurb, newnurb, cu,
1979                                                                 starta, starta + diffa, cu->actvert - starta);
1980                                                 }
1981
1982                                                 newnu = BKE_nurb_copy(nu, newu, 1);
1983                                                 memcpy(newnu->bezt, &nu->bezt[starta], diffa * sizeof(BezTriple));
1984                                                 if (newu != diffa) {
1985                                                         memcpy(&newnu->bezt[diffa], nu->bezt, cyclicu * sizeof(BezTriple));
1986                                                         if (i == cu->actnu) {
1987                                                                 calc_duplicate_actvert(
1988                                                                         editnurb, newnurb, cu,
1989                                                                         0, cyclicu, newu - cyclicu + cu->actvert);
1990                                                         }
1991                                                         cyclicu = 0;
1992                                                 }
1993
1994                                                 if (newu != nu->pntsu) newnu->flagu &= ~CU_NURB_CYCLIC;
1995
1996                                                 for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
1997                                                         select_beztriple(bezt1, SELECT, flag, HIDDEN);
1998                                                 }
1999
2000                                                 BLI_addtail(newnurb, newnu);
2001                                         }
2002                                 }
2003                         }
2004
2005                         if (cyclicu != 0) {
2006                                 if (i == cu->actnu) {
2007                                         calc_duplicate_actvert(
2008                                                 editnurb, newnurb, cu,
2009                                                 0, cyclicu, cu->actvert);
2010                                 }
2011
2012                                 newnu = BKE_nurb_copy(nu, cyclicu, 1);
2013                                 memcpy(newnu->bezt, nu->bezt, cyclicu * sizeof(BezTriple));
2014                                 newnu->flagu &= ~CU_NURB_CYCLIC;
2015
2016                                 for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
2017                                         select_beztriple(bezt1, SELECT, flag, HIDDEN);
2018                                 }
2019
2020                                 BLI_addtail(newnurb, newnu);
2021                         }
2022                 }
2023                 else if (nu->pntsv == 1) {    /* because UV Nurb has a different method for dupli */
2024                         for (a = 0, bp = nu->bp; a < nu->pntsu; a++, bp++) {
2025                                 enda = -1;
2026                                 starta = a;
2027                                 while (bp->f1 & flag) {
2028                                         if (!split) select_bpoint(bp, DESELECT, flag, HIDDEN);
2029                                         enda = a;
2030                                         if (a >= nu->pntsu - 1) break;
2031                                         a++;
2032                                         bp++;
2033                                 }
2034                                 if (enda >= starta) {
2035                                         newu = diffa = enda - starta + 1; /* set newu and diffa, may use both */
2036
2037                                         if (starta == 0 && newu != nu->pntsu && (nu->flagu & CU_NURB_CYCLIC)) {
2038                                                 cyclicu = newu;
2039                                         }
2040                                         else {
2041                                                 if (enda == nu->pntsu - 1) newu += cyclicu;
2042                                                 if (i == cu->actnu) {
2043                                                         calc_duplicate_actvert(
2044                                                                 editnurb, newnurb, cu,
2045                                                                 starta, starta + diffa, cu->actvert - starta);
2046                                                 }
2047
2048                                                 newnu = BKE_nurb_copy(nu, newu, 1);
2049                                                 memcpy(newnu->bp, &nu->bp[starta], diffa * sizeof(BPoint));
2050                                                 if (newu != diffa) {
2051                                                         memcpy(&newnu->bp[diffa], nu->bp, cyclicu * sizeof(BPoint));
2052                                                         if (i == cu->actnu) {
2053                                                                 calc_duplicate_actvert(
2054                                                                         editnurb, newnurb, cu,
2055                                                                         0, cyclicu, newu - cyclicu + cu->actvert);
2056                                                         }
2057                                                         cyclicu = 0;
2058                                                 }
2059
2060                                                 if (newu != nu->pntsu) newnu->flagu &= ~CU_NURB_CYCLIC;
2061
2062                                                 for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
2063                                                         select_bpoint(bp1, SELECT, flag, HIDDEN);
2064                                                 }
2065
2066                                                 BLI_addtail(newnurb, newnu);
2067                                         }
2068                                 }
2069                         }
2070
2071                         if (cyclicu != 0) {
2072                                 if (i == cu->actnu) {
2073                                         calc_duplicate_actvert(
2074                                                 editnurb, newnurb, cu,
2075                                                 0, cyclicu, cu->actvert);
2076                                 }
2077
2078                                 newnu = BKE_nurb_copy(nu, cyclicu, 1);
2079                                 memcpy(newnu->bp, nu->bp, cyclicu * sizeof(BPoint));
2080                                 newnu->flagu &= ~CU_NURB_CYCLIC;
2081
2082                                 for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
2083                                         select_bpoint(bp1, SELECT, flag, HIDDEN);
2084                                 }
2085
2086                                 BLI_addtail(newnurb, newnu);
2087                         }
2088                 }
2089                 else {
2090                         if (ED_curve_nurb_select_check(cu, nu)) {
2091                                 /* a rectangular area in nurb has to be selected and if splitting must be in U or V direction */
2092                                 usel = MEM_callocN(nu->pntsu, "adduplicateN3");
2093                                 bp = nu->bp;
2094                                 for (a = 0; a < nu->pntsv; a++) {
2095                                         for (b = 0; b < nu->pntsu; b++, bp++) {
2096                                                 if (bp->f1 & flag) usel[b]++;
2097                                         }
2098                                 }
2099                                 newu = 0;
2100                                 newv = 0;
2101                                 for (a = 0; a < nu->pntsu; a++) {
2102                                         if (usel[a]) {
2103                                                 if (newv == 0 || usel[a] == newv) {
2104                                                         newv = usel[a];
2105                                                         newu++;
2106                                                 }
2107                                                 else {
2108                                                         newv = 0;
2109                                                         break;
2110                                                 }
2111                                         }
2112                                 }
2113                                 MEM_freeN(usel);
2114
2115                                 if ((newu == 0 || newv == 0) ||
2116                                     (split && !isNurbselU(nu, &newv, SELECT) && !isNurbselV(nu, &newu, SELECT)))
2117                                 {
2118                                         if (G.debug & G_DEBUG)
2119                                                 printf("Can't duplicate Nurb\n");
2120                                 }
2121                                 else {
2122                                         for (a = 0, bp1 = nu->bp; a < nu->pntsu * nu->pntsv; a++, bp1++) {
2123                                                 newv = newu = 0;
2124
2125                                                 if ((bp1->f1 & flag) && !(bp1->f1 & SURF_SEEN)) {
2126                                                         /* point selected, now loop over points in U and V directions */
2127                                                         for (b = a % nu->pntsu, bp2 = bp1; b < nu->pntsu; b++, bp2++) {
2128                                                                 if (bp2->f1 & flag) {
2129                                                                         newu++;
2130                                                                         for (c = a / nu->pntsu, bp3 = bp2; c < nu->pntsv; c++, bp3 += nu->pntsu) {
2131                                                                                 if (bp3->f1 & flag) {
2132                                                                                         bp3->f1 |= SURF_SEEN; /* flag as seen so skipped on future iterations */
2133                                                                                         if (newu == 1) newv++;
2134                                                                                 }
2135                                                                                 else {
2136                                                                                         break;
2137                                                                                 }
2138                                                                         }
2139                                                                 }
2140                                                                 else {
2141                                                                         break;
2142                                                                 }
2143                                                         }
2144                                                 }
2145
2146                                                 if ((newu + newv) > 2) {
2147                                                         /* ignore single points */
2148                                                         if (a == 0) {
2149                                                                 /* check if need to save cyclic selection and continue if so */
2150                                                                 if (newu == nu->pntsu && (nu->flagv & CU_NURB_CYCLIC)) cyclicv = newv;
2151                                                                 if (newv == nu->pntsv && (nu->flagu & CU_NURB_CYCLIC)) cyclicu = newu;
2152                                                                 if (cyclicu != 0 || cyclicv != 0) continue;
2153                                                         }
2154
2155                                                         if (a + newu == nu->pntsu && cyclicu != 0) {
2156                                                                 /* cyclic in U direction */
2157                                                                 newnu = BKE_nurb_copy(nu, newu + cyclicu, newv);
2158                                                                 for (b = 0; b < newv; b++) {
2159                                                                         memcpy(&newnu->bp[b * newnu->pntsu], &nu->bp[b * nu->pntsu + a], newu * sizeof(BPoint));
2160                                                                         memcpy(&newnu->bp[b * newnu->pntsu + newu], &nu->bp[b * nu->pntsu], cyclicu * sizeof(BPoint));
2161                                                                 }
2162
2163                                                                 if (cu->actnu == i) {
2164                                                                         for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2165                                                                                 starta = b * nu->pntsu + a;
2166                                                                                 if (calc_duplicate_actvert(
2167                                                                                         editnurb, newnurb, cu,
2168                                                                                         cu->actvert, starta,
2169                                                                                         cu->actvert % nu->pntsu + newu + b * newnu->pntsu))
2170                                                                                 {
2171                                                                                         /* actvert in cyclicu selection */
2172                                                                                         break;
2173                                                                                 }
2174                                                                                 else if (calc_duplicate_actvert(
2175                                                                                              editnurb, newnurb, cu,
2176                                                                                              starta, starta + newu,
2177                                                                                              cu->actvert - starta + b * newnu->pntsu))
2178                                                                                 {
2179                                                                                         /* actvert in 'current' iteration selection */
2180                                                                                         break;
2181                                                                                 }
2182                                                                         }
2183                                                                 }
2184                                                                 cyclicu = cyclicv = 0;
2185                                                         }
2186                                                         else if ((a / nu->pntsu) + newv == nu->pntsv && cyclicv != 0) {
2187                                                                 /* cyclic in V direction */
2188                                                                 newnu = BKE_nurb_copy(nu, newu, newv + cyclicv);
2189                                                                 memcpy(newnu->bp, &nu->bp[a], newu * newv * sizeof(BPoint));
2190                                                                 memcpy(&newnu->bp[newu * newv], nu->bp, newu * cyclicv * sizeof(BPoint));
2191
2192                                                                 /* check for actvert in cylicv selection */
2193                                                                 if (cu->actnu == i) {
2194                                                                         calc_duplicate_actvert(
2195                                                                                 editnurb, newnurb, cu,
2196                                                                                 cu->actvert, a,
2197                                                                                 (newu * newv) + cu->actvert);
2198                                                                 }
2199                                                                 cyclicu = cyclicv = 0;
2200                                                         }
2201                                                         else {
2202                                                                 newnu = BKE_nurb_copy(nu, newu, newv);
2203                                                                 for (b = 0; b < newv; b++) {
2204                                                                         memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu + a], newu * sizeof(BPoint));
2205                                                                 }
2206                                                         }
2207
2208                                                         /* general case if not handled by cyclicu or cyclicv */
2209                                                         if (cu->actnu == i) {
2210                                                                 for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2211                                                                         starta = b * nu->pntsu + a;
2212                                                                         if (calc_duplicate_actvert(
2213                                                                                 editnurb, newnurb, cu,
2214                                                                                 starta, starta + newu,
2215                                                                                 cu->actvert - (a / nu->pntsu * nu->pntsu + diffa + (starta % nu->pntsu))))
2216                                                                         {
2217                                                                                 break;
2218                                                                         }
2219                                                                 }
2220                                                         }
2221                                                         BLI_addtail(newnurb, newnu);
2222
2223                                                         if (newu != nu->pntsu) newnu->flagu &= ~CU_NURB_CYCLIC;
2224                                                         if (newv != nu->pntsv) newnu->flagv &= ~CU_NURB_CYCLIC;
2225                                                 }
2226                                         }
2227
2228                                         if (cyclicu != 0 || cyclicv != 0) {
2229                                                 /* copy start of a cyclic surface, or copying all selected points */
2230                                                 newu = cyclicu == 0 ? nu->pntsu : cyclicu;
2231                                                 newv = cyclicv == 0 ? nu->pntsv : cyclicv;
2232
2233                                                 newnu = BKE_nurb_copy(nu, newu, newv);
2234                                                 for (b = 0; b < newv; b++) {
2235                                                         memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu], newu * sizeof(BPoint));
2236                                                 }
2237
2238                                                 /* check for actvert in the unused cyclicuv selection */
2239                                                 if (cu->actnu == i) {
2240                                                         for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2241                                                                 starta = b * nu->pntsu;
2242                                                                 if (calc_duplicate_actvert(
2243                                                                         editnurb, newnurb, cu,
2244                                                                         starta, starta + newu,
2245                                                                         cu->actvert - (diffa + (starta % nu->pntsu))))
2246                                                                 {
2247                                                                         break;
2248                                                                 }
2249                                                         }
2250                                                 }
2251                                                 BLI_addtail(newnurb, newnu);
2252
2253                                                 if (newu != nu->pntsu) newnu->flagu &= ~CU_NURB_CYCLIC;
2254                                                 if (newv != nu->pntsv) newnu->flagv &= ~CU_NURB_CYCLIC;
2255                                         }
2256
2257                                         for (b = 0, bp1 = nu->bp; b < nu->pntsu * nu->pntsv; b++, bp1++) {
2258                                                 bp1->f1 &= ~SURF_SEEN;
2259                                                 if (!split) select_bpoint(bp1, DESELECT, flag, HIDDEN);
2260                                         }
2261                                 }
2262                         }
2263                 }
2264         }
2265
2266         if (BLI_listbase_is_empty(newnurb) == false) {
2267                 for (nu = newnurb->first; nu; nu = nu->next) {
2268                         if (nu->type == CU_BEZIER) {
2269                                 if (split) {
2270                                         /* recalc first and last */
2271                                         BKE_nurb_handle_calc_simple(nu, &nu->bezt[0]);
2272                                         BKE_nurb_handle_calc_simple(nu, &nu->bezt[nu->pntsu - 1]);
2273                                 }
2274                         }
2275                         else {
2276                                 /* knots done after duplicate as pntsu may change */
2277                                 BKE_nurb_order_clamp_u(nu);
2278                                 BKE_nurb_knot_calc_u(nu);
2279
2280                                 if (obedit->type == OB_SURF) {
2281                                         for (a = 0, bp = nu->bp; a < nu->pntsu * nu->pntsv; a++, bp++) {
2282                                                 bp->f1 &= ~SURF_SEEN;
2283                                         }
2284
2285                                         BKE_nurb_order_clamp_v(nu);
2286                                         BKE_nurb_knot_calc_v(nu);
2287                                 }
2288                         }
2289                 }
2290         }
2291 }
2292
2293 /**************** switch direction operator ***************/
2294
2295 static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
2296 {
2297         Object *obedit = CTX_data_edit_object(C);
2298         Curve *cu = (Curve *)obedit->data;
2299         EditNurb *editnurb = cu->editnurb;
2300         Nurb *nu;
2301         int i;
2302
2303         for (nu = editnurb->nurbs.first, i = 0; nu; nu = nu->next, i++) {
2304                 if (ED_curve_nurb_select_check(cu, nu)) {
2305                         BKE_nurb_direction_switch(nu);
2306                         keyData_switchDirectionNurb(cu, nu);
2307                         if ((i == cu->actnu) && (cu->actvert != CU_ACT_NONE)) {
2308                                 cu->actvert = (nu->pntsu - 1) - cu->actvert;
2309                         }
2310                 }
2311         }
2312
2313         if (ED_curve_updateAnimPaths(obedit->data))
2314                 WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
2315
2316         DAG_id_tag_update(obedit->data, 0);
2317         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2318
2319         return OPERATOR_FINISHED;
2320 }
2321
2322 void CURVE_OT_switch_direction(wmOperatorType *ot)
2323 {
2324         /* identifiers */
2325         ot->name = "Switch Direction";
2326         ot->description = "Switch direction of selected splines";
2327         ot->idname = "CURVE_OT_switch_direction";
2328         
2329         /* api callbacks */
2330         ot->exec = switch_direction_exec;
2331         ot->poll = ED_operator_editsurfcurve;
2332
2333         /* flags */
2334         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2335 }
2336
2337 /****************** set weight operator *******************/
2338
2339 static int set_goal_weight_exec(bContext *C, wmOperator *op)
2340 {
2341         Object *obedit = CTX_data_edit_object(C);
2342         ListBase *editnurb = object_editcurve_get(obedit);
2343         Nurb *nu;
2344         BezTriple *bezt;
2345         BPoint *bp;
2346         float weight = RNA_float_get(op->ptr, "weight");
2347         int a;
2348                                 
2349         for (nu = editnurb->first; nu; nu = nu->next) {
2350                 if (nu->bezt) {
2351                         for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
2352                                 if (bezt->f2 & SELECT)
2353                                         bezt->weight = weight;
2354                         }
2355                 }
2356                 else if (nu->bp) {
2357                         for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
2358                                 if (bp->f1 & SELECT)
2359                                         bp->weight = weight;
2360                         }
2361                 }
2362         }
2363
2364         DAG_id_tag_update(obedit->data, 0);
2365         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2366
2367         return OPERATOR_FINISHED;
2368 }
2369
2370 void CURVE_OT_spline_weight_set(wmOperatorType *ot)
2371 {
2372         /* identifiers */
2373         ot->name = "Set Goal Weight";
2374         ot->description = "Set softbody goal weight for selected points";
2375         ot->idname = "CURVE_OT_spline_weight_set";
2376         
2377         /* api callbacks */
2378         ot->exec = set_goal_weight_exec;
2379         ot->invoke = WM_operator_props_popup;
2380         ot->poll = ED_operator_editsurfcurve;
2381
2382         /* flags */
2383         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2384
2385         /* properties */
2386         RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
2387 }
2388
2389 /******************* set radius operator ******************/
2390
2391 static int set_radius_exec(bContext *C, wmOperator *op)
2392 {
2393         Object *obedit = CTX_data_edit_object(C);
2394         ListBase *editnurb = object_editcurve_get(obedit);
2395         Nurb *nu;
2396         BezTriple *bezt;
2397         BPoint *bp;
2398         float radius = RNA_float_get(op->ptr, "radius");
2399         int a;
2400         
2401         for (nu = editnurb->first; nu; nu = nu->next) {
2402                 if (nu->bezt) {
2403                         for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
2404                                 if (bezt->f2 & SELECT)
2405                                         bezt->radius = radius;
2406                         }
2407                 }
2408                 else if (nu->bp) {
2409                         for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
2410                                 if (bp->f1 & SELECT)
2411                                         bp->radius = radius;
2412                         }
2413                 }
2414         }
2415
2416         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2417         DAG_id_tag_update(obedit->data, 0);
2418
2419         return OPERATOR_FINISHED;
2420 }
2421
2422 void CURVE_OT_radius_set(wmOperatorType *ot)
2423 {
2424         /* identifiers */
2425         ot->name = "Set Curve Radius";
2426         ot->description = "Set per-point radius which is used for bevel tapering";
2427         ot->idname = "CURVE_OT_radius_set";
2428         
2429         /* api callbacks */
2430         ot->exec = set_radius_exec;
2431         ot->invoke = WM_operator_props_popup;
2432         ot->poll = ED_operator_editsurfcurve;
2433
2434         /* flags */
2435         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2436
2437         /* properties */
2438         RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.0001f, 10.0f);
2439 }
2440
2441 /********************* smooth operator ********************/
2442
2443 static void smooth_single_bezt(
2444         BezTriple *bezt,
2445         const BezTriple *bezt_orig_prev, const BezTriple *bezt_orig_next,
2446         float factor)
2447 {
2448         int i;
2449
2450         BLI_assert(IN_RANGE_INCL(factor, 0.0f, 1.0f));
2451
2452         for (i = 0; i < 3; i++) {
2453                 float val_old, val_new, offset;
2454
2455                 /* get single dimension pos of the mid handle */
2456                 val_old = bezt->vec[1][i];
2457
2458                 /* get the weights of the previous/next mid handles and calc offset */
2459                 val_new = (bezt_orig_prev->vec[1][i] * 0.5f) + (bezt_orig_next->vec[1][i] * 0.5f);
2460                 offset = (val_old * (1.0f - factor)) + (val_new * factor) - val_old;
2461
2462                 /* offset midpoint and 2 handles */
2463                 bezt->vec[1][i] += offset;
2464                 bezt->vec[0][i] += offset;
2465                 bezt->vec[2][i] += offset;
2466         }
2467 }
2468
2469 /**
2470  * Same as smooth_single_bezt(), keep in sync
2471  */
2472 static void smooth_single_bp(
2473         BPoint *bp,
2474         const BPoint *bp_orig_prev, const BPoint *bp_orig_next,
2475         float factor)
2476 {
2477         int i;
2478
2479         BLI_assert(IN_RANGE_INCL(factor, 0.0f, 1.0f));
2480
2481         for (i = 0; i < 3; i++) {
2482                 float val_old, val_new, offset;
2483
2484                 val_old = bp->vec[i];
2485                 val_new = (bp_orig_prev->vec[i] * 0.5f) + (bp_orig_next->vec[i] * 0.5f);
2486                 offset = (val_old * (1.0f - factor)) + (val_new * factor) - val_old;
2487
2488                 bp->vec[i] += offset;
2489         }
2490 }
2491
2492 static int smooth_exec(bContext *C, wmOperator *UNUSED(op))
2493 {
2494         const float factor = 1.0f / 6.0f;
2495         Object *obedit = CTX_data_edit_object(C);
2496         ListBase *editnurb = object_editcurve_get(obedit);
2497         Nurb *nu;
2498
2499         int a, a_end;
2500         bool changed = false;
2501
2502         for (nu = editnurb->first; nu; nu = nu->next) {
2503                 if (nu->bezt) {
2504                         /* duplicate the curve to use in weight calculation */
2505                         const BezTriple *bezt_orig = MEM_dupallocN(nu->bezt);
2506                         BezTriple *bezt;
2507                         changed = false;
2508
2509                         /* check whether its cyclic or not, and set initial & final conditions */
2510                         if (nu->flagu & CU_NURB_CYCLIC) {
2511                                 a = 0;
2512                                 a_end = nu->pntsu;
2513                         }
2514                         else {
2515                                 a = 1;
2516                                 a_end = nu->pntsu - 1;
2517                         }
2518
2519                         /* for all the curve points */
2520                         for (; a < a_end; a++) {
2521                                 /* respect selection */
2522                                 bezt = &nu->bezt[a];
2523                                 if (bezt->f2 & SELECT) {
2524                                         const BezTriple *bezt_orig_prev, *bezt_orig_next;
2525
2526                                         bezt_orig_prev = &bezt_orig[mod_i(a - 1, nu->pntsu)];
2527                                         bezt_orig_next = &bezt_orig[mod_i(a + 1, nu->pntsu)];
2528
2529                                         smooth_single_bezt(bezt, bezt_orig_prev, bezt_orig_next, factor);
2530
2531                                         changed = true;
2532                                 }
2533                         }
2534                         MEM_freeN((void *)bezt_orig);
2535                         if (changed) {
2536                                 BKE_nurb_handles_calc(nu);
2537                         }
2538                 }
2539                 else if (nu->bp) {
2540                         /* Same as above, keep these the same! */
2541                         const BPoint *bp_orig = MEM_dupallocN(nu->bp);
2542                         BPoint *bp;
2543
2544                         if (nu->flagu & CU_NURB_CYCLIC) {
2545                                 a = 0;
2546                                 a_end = nu->pntsu;
2547                         }
2548                         else {
2549                                 a = 1;
2550                                 a_end = nu->pntsu - 1;
2551                         }
2552
2553                         for (; a < a_end; a++) {
2554                                 bp = &nu->bp[a];
2555                                 if (bp->f1 & SELECT) {
2556                                         const BPoint *bp_orig_prev, *bp_orig_next;
2557
2558                                         bp_orig_prev = &bp_orig[mod_i(a - 1, nu->pntsu)];
2559                                         bp_orig_next = &bp_orig[mod_i(a + 1, nu->pntsu)];
2560
2561                                         smooth_single_bp(bp, bp_orig_prev, bp_orig_next, factor);
2562                                 }
2563                         }
2564                         MEM_freeN((void *)bp_orig);
2565                 }
2566         }
2567
2568         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2569         DAG_id_tag_update(obedit->data, 0);
2570
2571         return OPERATOR_FINISHED;
2572 }
2573
2574 void CURVE_OT_smooth(wmOperatorType *ot)
2575 {
2576         /* identifiers */
2577         ot->name = "Smooth";
2578         ot->description = "Flatten angles of selected points";
2579         ot->idname = "CURVE_OT_smooth";
2580         
2581         /* api callbacks */
2582         ot->exec = smooth_exec;
2583         ot->poll = ED_operator_editsurfcurve;
2584
2585         /* flags */
2586         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2587 }
2588
2589 /* -------------------------------------------------------------------- */
2590 /* Smooth radius/weight/tilt
2591  *
2592  * TODO: make smoothing distance based
2593  * TODO: support cyclic curves
2594  */
2595
2596 static void curve_smooth_value(ListBase *editnurb,
2597                                const int bezt_offsetof, const int bp_offset)
2598 {
2599         Nurb *nu;
2600         BezTriple *bezt;
2601         BPoint *bp;
2602         int a;
2603
2604         /* use for smoothing */
2605         int last_sel;
2606         int start_sel, end_sel; /* selection indices, inclusive */
2607         float start_rad, end_rad, fac, range;
2608
2609         for (nu = editnurb->first; nu; nu = nu->next) {
2610                 if (nu->bezt) {
2611 #define BEZT_VALUE(bezt) (*((float *)((char *)(bezt) + bezt_offsetof)))
2612
2613                         for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
2614                                 /* loop over selection segments of a curve, smooth each */
2615
2616                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
2617                                 start_sel = -1;
2618                                 for (bezt = &nu->bezt[last_sel], a = last_sel; a < nu->pntsu; a++, bezt++) {
2619                                         if (bezt->f2 & SELECT) {
2620                                                 start_sel = a;
2621                                                 break;
2622                                         }
2623                                 }
2624                                 /* in case there are no other selected verts */
2625                                 end_sel = start_sel;
2626                                 for (bezt = &nu->bezt[start_sel + 1], a = start_sel + 1; a < nu->pntsu; a++, bezt++) {
2627                                         if ((bezt->f2 & SELECT) == 0) {
2628                                                 break;
2629                                         }
2630                                         end_sel = a;
2631                                 }
2632
2633                                 if (start_sel == -1) {
2634                                         last_sel = nu->pntsu; /* next... */
2635                                 }
2636                                 else {
2637                                         last_sel = end_sel; /* before we modify it */
2638
2639                                         /* now blend between start and end sel */
2640                                         start_rad = end_rad = FLT_MAX;
2641
2642                                         if (start_sel == end_sel) {
2643                                                 /* simple, only 1 point selected */
2644                                                 if (start_sel > 0)                         start_rad = BEZT_VALUE(&nu->bezt[start_sel - 1]);
2645                                                 if (end_sel != -1 && end_sel < nu->pntsu)  end_rad   = BEZT_VALUE(&nu->bezt[start_sel + 1]);
2646
2647                                                 if      (start_rad != FLT_MAX && end_rad >= FLT_MAX) BEZT_VALUE(&nu->bezt[start_sel]) = (start_rad + end_rad) / 2.0f;
2648                                                 else if (start_rad != FLT_MAX)                       BEZT_VALUE(&nu->bezt[start_sel]) = start_rad;
2649                                                 else if (end_rad   != FLT_MAX)                       BEZT_VALUE(&nu->bezt[start_sel]) = end_rad;
2650                                         }
2651                                         else {
2652                                                 /* if endpoints selected, then use them */
2653                                                 if (start_sel == 0) {
2654                                                         start_rad = BEZT_VALUE(&nu->bezt[start_sel]);
2655                                                         start_sel++; /* we don't want to edit the selected endpoint */
2656                                                 }
2657                                                 else {
2658                                                         start_rad = BEZT_VALUE(&nu->bezt[start_sel - 1]);
2659                                                 }
2660                                                 if (end_sel == nu->pntsu - 1) {
2661                                                         end_rad = BEZT_VALUE(&nu->bezt[end_sel]);
2662                                                         end_sel--; /* we don't want to edit the selected endpoint */
2663                                                 }
2664                                                 else {
2665                                                         end_rad = BEZT_VALUE(&nu->bezt[end_sel + 1]);
2666                                                 }
2667
2668                                                 /* Now Blend between the points */
2669                                                 range = (float)(end_sel - start_sel) + 2.0f;
2670                                                 for (bezt = &nu->bezt[start_sel], a = start_sel; a <= end_sel; a++, bezt++) {
2671                                                         fac = (float)(1 + a - start_sel) / range;
2672                                                         BEZT_VALUE(bezt) = start_rad * (1.0f - fac) + end_rad * fac;
2673                                                 }
2674                                         }
2675                                 }
2676                         }
2677 #undef BEZT_VALUE
2678                 }
2679                 else if (nu->bp) {
2680 #define BP_VALUE(bp) (*((float *)((char *)(bp) + bp_offset)))
2681
2682                         /* Same as above,&nbs