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