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