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