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