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