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