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