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