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