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