code cleanup: use const events for modal and invoke operators.
[blender.git] / source / blender / editors / curve / editcurve.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/curve/editcurve.c
29  *  \ingroup edcurve
30  */
31
32 #include <math.h>
33 #include <string.h>
34
35 #ifndef WIN32
36 #include <unistd.h>
37 #else
38 #include <io.h>
39 #endif
40 #include <stdlib.h>
41
42 #include "DNA_key_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_anim_types.h"
46
47 #include "MEM_guardedalloc.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_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, char *orig_rna_path, char *rna_path, ListBase *orig_curves, ListBase *curves)
1032 {
1033         FCurve *fcu, *nfcu, *nextfcu;
1034         int len = strlen(orig_rna_path);
1035
1036         for (fcu = orig_curves->first; fcu; fcu = nextfcu) {
1037                 nextfcu = fcu->next;
1038                 if (!strncmp(fcu->rna_path, orig_rna_path, len)) {
1039                         char *spath, *suffix = fcu->rna_path + len;
1040                         nfcu = copy_fcurve(fcu);
1041                         spath = nfcu->rna_path;
1042                         nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix);
1043                         BLI_addtail(curves, nfcu);
1044
1045                         if (fcu->grp) {
1046                                 action_groups_remove_channel(adt->action, fcu);
1047                                 action_groups_add_channel(adt->action, fcu->grp, nfcu);
1048                         }
1049                         else if ((adt->action) && (&adt->action->curves == orig_curves))
1050                                 BLI_remlink(&adt->action->curves, fcu);
1051                         else
1052                                 BLI_remlink(&adt->drivers, fcu);
1053
1054                         free_fcurve(fcu);
1055
1056                         MEM_freeN(spath);
1057                 }
1058         }
1059 }
1060
1061 static void fcurve_remove(AnimData *adt, ListBase *orig_curves, FCurve *fcu)
1062 {
1063         if (orig_curves == &adt->drivers) BLI_remlink(&adt->drivers, fcu);
1064         else action_groups_remove_channel(adt->action, fcu);
1065
1066         free_fcurve(fcu);
1067 }
1068
1069 static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
1070 {
1071         int nu_index = 0, a, pt_index;
1072         EditNurb *editnurb = cu->editnurb;
1073         Nurb *nu = editnurb->nurbs.first;
1074         CVKeyIndex *keyIndex;
1075         char rna_path[64], orig_rna_path[64];
1076         AnimData *adt = BKE_animdata_from_id(&cu->id);
1077         ListBase curves = {NULL, NULL};
1078         FCurve *fcu, *next;
1079
1080         for (nu = editnurb->nurbs.first, nu_index = 0;  nu != NULL;  nu = nu->next, nu_index++) {
1081                 if (nu->bezt) {
1082                         BezTriple *bezt = nu->bezt;
1083                         a = nu->pntsu;
1084                         pt_index = 0;
1085
1086                         while (a--) {
1087                                 keyIndex = getCVKeyIndex(editnurb, bezt);
1088                                 if (keyIndex) {
1089                                         BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d].bezier_points[%d]", nu_index, pt_index);
1090                                         BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d].bezier_points[%d]", keyIndex->nu_index, keyIndex->pt_index);
1091
1092                                         if (keyIndex->switched) {
1093                                                 char handle_path[64], orig_handle_path[64];
1094                                                 BLI_snprintf(orig_handle_path, sizeof(orig_rna_path), "%s.handle_left", orig_rna_path);
1095                                                 BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_right", rna_path);
1096                                                 fcurve_path_rename(adt, orig_handle_path, handle_path, orig_curves, &curves);
1097
1098                                                 BLI_snprintf(orig_handle_path, sizeof(orig_rna_path), "%s.handle_right", orig_rna_path);
1099                                                 BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_left", rna_path);
1100                                                 fcurve_path_rename(adt, orig_handle_path, handle_path, orig_curves, &curves);
1101                                         }
1102
1103                                         fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1104
1105                                         keyIndex->nu_index = nu_index;
1106                                         keyIndex->pt_index = pt_index;
1107                                 }
1108
1109                                 bezt++;
1110                                 pt_index++;
1111                         }
1112                 }
1113                 else {
1114                         BPoint *bp = nu->bp;
1115                         a = nu->pntsu * nu->pntsv;
1116                         pt_index = 0;
1117
1118                         while (a--) {
1119                                 keyIndex = getCVKeyIndex(editnurb, bp);
1120                                 if (keyIndex) {
1121                                         BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d].points[%d]", nu_index, pt_index);
1122                                         BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d].points[%d]", keyIndex->nu_index, keyIndex->pt_index);
1123                                         fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1124
1125                                         keyIndex->nu_index = nu_index;
1126                                         keyIndex->pt_index = pt_index;
1127                                 }
1128
1129                                 bp++;
1130                                 pt_index++;
1131                         }
1132                 }
1133         }
1134
1135         /* remove paths for removed control points
1136          * need this to make further step with copying non-cv related curves copying
1137          * not touching cv's f-curves */
1138         for (fcu = orig_curves->first; fcu; fcu = next) {
1139                 next = fcu->next;
1140
1141                 if (!strncmp(fcu->rna_path, "splines", 7)) {
1142                         char *ch = strchr(fcu->rna_path, '.');
1143
1144                         if (ch && (!strncmp(ch, ".bezier_points", 14) || !strncmp(ch, ".points", 7)))
1145                                 fcurve_remove(adt, orig_curves, fcu);
1146                 }
1147         }
1148
1149         for (nu = editnurb->nurbs.first, nu_index = 0;  nu != NULL;  nu = nu->next, nu_index++) {
1150                 keyIndex = NULL;
1151                 if (nu->pntsu) {
1152                         if (nu->bezt) keyIndex = getCVKeyIndex(editnurb, &nu->bezt[0]);
1153                         else keyIndex = getCVKeyIndex(editnurb, &nu->bp[0]);
1154                 }
1155
1156                 if (keyIndex) {
1157                         BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d]", nu_index);
1158                         BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d]", keyIndex->nu_index);
1159                         fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1160                 }
1161         }
1162
1163         /* the remainders in orig_curves can be copied back (like follow path) */
1164         /* (if it's not path to spline) */
1165         for (fcu = orig_curves->first; fcu; fcu = next) {
1166                 next = fcu->next;
1167
1168                 if (!strncmp(fcu->rna_path, "splines", 7)) fcurve_remove(adt, orig_curves, fcu);
1169                 else BLI_addtail(&curves, fcu);
1170         }
1171
1172         *orig_curves = curves;
1173 }
1174
1175 /* return 0 if animation data wasn't changed, 1 otherwise */
1176 int ED_curve_updateAnimPaths(Curve *cu)
1177 {
1178         AnimData *adt = BKE_animdata_from_id(&cu->id);
1179
1180         if (!curve_is_animated(cu)) return 0;
1181
1182         if (adt->action)
1183                 curve_rename_fcurves(cu, &adt->action->curves);
1184
1185         curve_rename_fcurves(cu, &adt->drivers);
1186
1187         return 1;
1188 }
1189
1190 /* ********************* LOAD and MAKE *************** */
1191
1192 /* load editNurb in object */
1193 void load_editNurb(Object *obedit)
1194 {
1195         ListBase *editnurb = object_editcurve_get(obedit);
1196
1197         if (obedit == NULL) return;
1198
1199         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1200                 Curve *cu = obedit->data;
1201                 Nurb *nu, *newnu;
1202                 ListBase newnurb = {NULL, NULL}, oldnurb = cu->nurb;
1203
1204                 for (nu = editnurb->first; nu; nu = nu->next) {
1205                         newnu = BKE_nurb_duplicate(nu);
1206                         BLI_addtail(&newnurb, newnu);
1207
1208                         if (nu->type == CU_NURBS) {
1209                                 BKE_nurb_order_clamp_u(nu);
1210                         }
1211                 }
1212
1213                 cu->nurb = newnurb;
1214
1215                 calc_shapeKeys(obedit);
1216                 ED_curve_updateAnimPaths(obedit->data);
1217
1218                 BKE_nurbList_free(&oldnurb);
1219         }
1220 }
1221
1222 /* make copy in cu->editnurb */
1223 void make_editNurb(Object *obedit)
1224 {
1225         Curve *cu = (Curve *)obedit->data;
1226         EditNurb *editnurb = cu->editnurb;
1227         Nurb *nu, *newnu, *nu_act = NULL;
1228         KeyBlock *actkey;
1229
1230         set_actNurb(obedit, NULL);
1231
1232         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1233                 actkey = BKE_keyblock_from_object(obedit);
1234
1235                 if (actkey) {
1236                         // XXX strcpy(G.editModeTitleExtra, "(Key) ");
1237                         undo_editmode_clear();
1238                         BKE_key_convert_to_curve(actkey, cu, &cu->nurb);
1239                 }
1240
1241                 if (editnurb) {
1242                         BKE_nurbList_free(&editnurb->nurbs);
1243                         BKE_curve_editNurb_keyIndex_free(editnurb);
1244                         editnurb->keyindex = NULL;
1245                 }
1246                 else {
1247                         editnurb = MEM_callocN(sizeof(EditNurb), "editnurb");
1248                         cu->editnurb = editnurb;
1249                 }
1250
1251                 nu = cu->nurb.first;
1252                 cu->lastsel = NULL;   /* for select row */
1253
1254                 while (nu) {
1255                         newnu = BKE_nurb_duplicate(nu);
1256                         BKE_nurb_test2D(newnu); // after join, or any other creation of curve
1257                         BLI_addtail(&editnurb->nurbs, newnu);
1258
1259                         if (nu_act == NULL && isNurbsel(nu)) {
1260                                 nu_act = newnu;
1261                                 set_actNurb(obedit, newnu);
1262                         }
1263
1264                         nu = nu->next;
1265                 }
1266
1267                 if (actkey)
1268                         editnurb->shapenr = obedit->shapenr;
1269
1270                 /* animation could be added in editmode even if there was no animdata i
1271                  * object mode hence we always need CVs index be created */
1272                 init_editNurb_keyIndex(editnurb, &cu->nurb);
1273         }
1274 }
1275
1276 void free_editNurb(Object *obedit)
1277 {
1278         Curve *cu = obedit->data;
1279
1280         BKE_curve_editNurb_free(cu);
1281 }
1282
1283 void CU_deselect_all(Object *obedit)
1284 {
1285         ListBase *editnurb = object_editcurve_get(obedit);
1286
1287         if (editnurb) {
1288                 Nurb *nu;
1289                 int a;
1290                 for (nu = editnurb->first; nu; nu = nu->next) {
1291                         if (nu->bezt) {
1292                                 BezTriple *bezt;
1293                                 for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
1294                                         bezt->f1 &= ~SELECT;
1295                                         bezt->f2 &= ~SELECT;
1296                                         bezt->f3 &= ~SELECT;
1297                                 }
1298                         }
1299                         else if (nu->bp) {
1300                                 BPoint *bp;
1301                                 for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
1302                                         bp->f1 &= ~SELECT;
1303                                 }
1304                         }
1305                 }
1306         }
1307 }
1308
1309 void CU_select_all(Object *obedit)
1310 {
1311         ListBase *editnurb = object_editcurve_get(obedit);
1312
1313         if (editnurb) {
1314                 Nurb *nu;
1315                 int a;
1316                 for (nu = editnurb->first; nu; nu = nu->next) {
1317                         if (nu->bezt) {
1318                                 BezTriple *bezt;
1319                                 for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
1320                                         if (bezt->hide == 0) {
1321                                                 bezt->f1 |= SELECT;
1322                                                 bezt->f2 |= SELECT;
1323                                                 bezt->f3 |= SELECT;
1324                                         }
1325                                 }
1326                         }
1327                         else if (nu->bp) {
1328                                 BPoint *bp;
1329                                 for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
1330                                         if (bp->hide == 0)
1331                                                 bp->f1 |= SELECT;
1332                                 }
1333                         }
1334                 }
1335         }
1336 }
1337
1338 void CU_select_swap(Object *obedit)
1339 {
1340         ListBase *editnurb = object_editcurve_get(obedit);
1341
1342         if (editnurb) {
1343                 Curve *cu = obedit->data;
1344                 Nurb *nu;
1345                 BPoint *bp;
1346                 BezTriple *bezt;
1347                 int a;
1348
1349                 cu->lastsel = NULL;
1350
1351                 for (nu = editnurb->first; nu; nu = nu->next) {
1352                         if (nu->type == CU_BEZIER) {
1353                                 bezt = nu->bezt;
1354                                 a = nu->pntsu;
1355                                 while (a--) {
1356                                         if (bezt->hide == 0) {
1357                                                 bezt->f2 ^= SELECT; /* always do the center point */
1358                                                 if ((cu->drawflag & CU_HIDE_HANDLES) == 0) {
1359                                                         bezt->f1 ^= SELECT;
1360                                                         bezt->f3 ^= SELECT;
1361                                                 }
1362                                         }
1363                                         bezt++;
1364                                 }
1365                         }
1366                         else {
1367                                 bp = nu->bp;
1368                                 a = nu->pntsu * nu->pntsv;
1369                                 while (a--) {
1370                                         swap_selection_bpoint(bp);
1371                                         bp++;
1372                                 }
1373                         }
1374                 }
1375         }
1376 }
1377
1378 /******************** separate operator ***********************/
1379
1380 static int separate_exec(bContext *C, wmOperator *op)
1381 {
1382         Main *bmain = CTX_data_main(C);
1383         Scene *scene = CTX_data_scene(C);
1384         Nurb *nu, *nu1;
1385         Object *oldob, *newob;
1386         Base *oldbase, *newbase;
1387         Curve *oldcu, *newcu;
1388         EditNurb *oldedit, *newedit;
1389
1390         oldbase = CTX_data_active_base(C);
1391         oldob = oldbase->object;
1392         oldcu = oldob->data;
1393         oldedit = oldcu->editnurb;
1394
1395         if (oldcu->key) {
1396                 BKE_report(op->reports, RPT_ERROR, "Cannot separate a curve with vertex keys");
1397                 return OPERATOR_CANCELLED;
1398         }
1399
1400         WM_cursor_wait(1);
1401         
1402         /* 1. duplicate the object and data */
1403         newbase = ED_object_add_duplicate(bmain, scene, oldbase, 0); /* 0 = fully linked */
1404         DAG_relations_tag_update(bmain);
1405
1406         ED_base_object_select(newbase, BA_DESELECT);
1407         newob = newbase->object;
1408
1409         newcu = newob->data = BKE_curve_copy(oldcu);
1410         newcu->editnurb = NULL;
1411         oldcu->id.us--; /* because new curve is a copy: reduce user count */
1412
1413         /* 2. put new object in editmode and clear it */
1414         make_editNurb(newob);
1415         newedit = newcu->editnurb;
1416         BKE_nurbList_free(&newedit->nurbs);
1417         BKE_curve_editNurb_keyIndex_free(newedit);
1418
1419         /* 3. move over parts from old object */
1420         for (nu = oldedit->nurbs.first; nu; nu = nu1) {
1421                 nu1 = nu->next;
1422
1423                 if (isNurbsel(nu)) {
1424                         BLI_remlink(&oldedit->nurbs, nu);
1425                         BLI_addtail(&newedit->nurbs, nu);
1426                 }
1427         }
1428
1429         /* 4. put old object out of editmode */
1430         load_editNurb(newob);
1431         free_editNurb(newob);
1432
1433         DAG_id_tag_update(&oldob->id, OB_RECALC_DATA);  /* this is the original one */
1434         DAG_id_tag_update(&newob->id, OB_RECALC_DATA);  /* this is the separated one */
1435
1436         WM_event_add_notifier(C, NC_GEOM | ND_DATA, oldob->data);
1437
1438         WM_cursor_wait(0);
1439
1440         return OPERATOR_FINISHED;
1441 }
1442
1443 void CURVE_OT_separate(wmOperatorType *ot)
1444 {
1445         /* identifiers */
1446         ot->name = "Separate";
1447         ot->idname = "CURVE_OT_separate";
1448         ot->description = "Separate (partly) selected curves or surfaces into a new object";
1449         
1450         /* api callbacks */
1451         ot->exec = separate_exec;
1452         ot->poll = ED_operator_editsurfcurve;
1453         
1454         /* flags */
1455         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1456 }
1457
1458 /* ******************* FLAGS ********************* */
1459
1460 static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
1461 {
1462         /* return (u != -1): 1 row in u-direction selected. U has value between 0-pntsv
1463          * return (v != -1): 1 column in v-direction selected. V has value between 0-pntsu
1464          */
1465         BPoint *bp;
1466         int a, b, sel;
1467
1468         *u = *v = -1;
1469
1470         bp = nu->bp;
1471         for (b = 0; b < nu->pntsv; b++) {
1472                 sel = 0;
1473                 for (a = 0; a < nu->pntsu; a++, bp++) {
1474                         if (bp->f1 & flag) sel++;
1475                 }
1476                 if (sel == nu->pntsu) {
1477                         if (*u == -1) *u = b;
1478                         else return 0;
1479                 }
1480                 else if (sel > 1) {
1481                         return 0;  /* because sel == 1 is still ok */
1482                 }
1483         }
1484
1485         for (a = 0; a < nu->pntsu; a++) {
1486                 sel = 0;
1487                 bp = &nu->bp[a];
1488                 for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
1489                         if (bp->f1 & flag) sel++;
1490                 }
1491                 if (sel == nu->pntsv) {
1492                         if (*v == -1) *v = a;
1493                         else return 0;
1494                 }
1495                 else if (sel > 1) {
1496                         return 0;
1497                 }
1498         }
1499
1500         if (*u == -1 && *v > -1) return 1;
1501         if (*v == -1 && *u > -1) return 1;
1502         return 0;
1503 }
1504
1505 static void setflagsNurb(ListBase *editnurb, short flag)
1506 {
1507         Nurb *nu;
1508         BezTriple *bezt;
1509         BPoint *bp;
1510         int a;
1511
1512         for (nu = editnurb->first; nu; nu = nu->next) {
1513                 if (nu->type == CU_BEZIER) {
1514                         a = nu->pntsu;
1515                         bezt = nu->bezt;
1516                         while (a--) {
1517                                 bezt->f1 = bezt->f2 = bezt->f3 = flag;
1518                                 bezt++;
1519                         }
1520                 }
1521                 else {
1522                         a = nu->pntsu * nu->pntsv;
1523                         bp = nu->bp;
1524                         while (a--) {
1525                                 bp->f1 = flag;
1526                                 bp++;
1527                         }
1528                 }
1529         }
1530 }
1531
1532 static void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float rotmat[3][3])
1533 {
1534         /* all verts with (flag & 'flag') rotate */
1535         Nurb *nu;
1536         BPoint *bp;
1537         int a;
1538
1539         for (nu = editnurb->first; nu; nu = nu->next) {
1540                 if (nu->type == CU_NURBS) {
1541                         bp = nu->bp;
1542                         a = nu->pntsu * nu->pntsv;
1543
1544                         while (a--) {
1545                                 if (bp->f1 & flag) {
1546                                         sub_v3_v3(bp->vec, cent);
1547                                         mul_m3_v3(rotmat, bp->vec);
1548                                         add_v3_v3(bp->vec, cent);
1549                                 }
1550                                 bp++;
1551                         }
1552                 }
1553         }
1554 }
1555
1556 static void translateflagNurb(ListBase *editnurb, short flag, const float vec[3])
1557 {
1558         /* all verts with ('flag' & flag) translate */
1559         Nurb *nu;
1560         BezTriple *bezt;
1561         BPoint *bp;
1562         int a;
1563
1564         for (nu = editnurb->first; nu; nu = nu->next) {
1565                 if (nu->type == CU_BEZIER) {
1566                         a = nu->pntsu;
1567                         bezt = nu->bezt;
1568                         while (a--) {
1569                                 if (bezt->f1 & flag) add_v3_v3(bezt->vec[0], vec);
1570                                 if (bezt->f2 & flag) add_v3_v3(bezt->vec[1], vec);
1571                                 if (bezt->f3 & flag) add_v3_v3(bezt->vec[2], vec);
1572                                 bezt++;
1573                         }
1574                 }
1575                 else {
1576                         a = nu->pntsu * nu->pntsv;
1577                         bp = nu->bp;
1578                         while (a--) {
1579                                 if (bp->f1 & flag) add_v3_v3(bp->vec, vec);
1580                                 bp++;
1581                         }
1582                 }
1583
1584                 BKE_nurb_test2D(nu);
1585         }
1586 }
1587
1588 static void weightflagNurb(ListBase *editnurb, short flag, float w)
1589 {
1590         Nurb *nu;
1591         BPoint *bp;
1592         int a;
1593
1594         for (nu = editnurb->first; nu; nu = nu->next) {
1595                 if (nu->type == CU_NURBS) {
1596                         a = nu->pntsu * nu->pntsv;
1597                         bp = nu->bp;
1598                         while (a--) {
1599                                 if (bp->f1 & flag) {
1600                                         /* a mode used to exist for replace/multiple but is was unused */
1601                                         bp->vec[3] *= w;
1602                                 }
1603                                 bp++;
1604                         }
1605                 }
1606         }
1607 }
1608
1609 static int deleteflagNurb(bContext *C, wmOperator *UNUSED(op), int flag)
1610 {
1611         Object *obedit = CTX_data_edit_object(C);
1612         Curve *cu = obedit->data;
1613         ListBase *editnurb = object_editcurve_get(obedit);
1614         Nurb *nu, *next;
1615         BPoint *bp, *bpn, *newbp;
1616         int a, b, newu, newv, sel;
1617
1618         if (obedit->type != OB_SURF) {
1619                 return OPERATOR_CANCELLED;
1620         }
1621
1622         cu->lastsel = NULL;
1623
1624         nu = editnurb->first;
1625         while (nu) {
1626                 next = nu->next;
1627
1628                 /* is entire nurb selected */
1629                 bp = nu->bp;
1630                 a = nu->pntsu * nu->pntsv;
1631                 while (a) {
1632                         a--;
1633                         if (bp->f1 & flag) {
1634                                 /* pass */
1635                         }
1636                         else {
1637                                 break;
1638                         }
1639                         bp++;
1640                 }
1641                 if (a == 0) {
1642                         BLI_remlink(editnurb, nu);
1643                         keyIndex_delNurb(cu->editnurb, nu);
1644                         BKE_nurb_free(nu); nu = NULL;
1645                 }
1646                 else {
1647                         /* is nurb in U direction selected */
1648                         newv = nu->pntsv;
1649                         bp = nu->bp;
1650                         for (b = 0; b < nu->pntsv; b++) {
1651                                 sel = 0;
1652                                 for (a = 0; a < nu->pntsu; a++, bp++) {
1653                                         if (bp->f1 & flag) sel++;
1654                                 }
1655                                 if (sel == nu->pntsu) {
1656                                         newv--;
1657                                 }
1658                                 else if (sel >= 1) {
1659                                         /* don't delete */
1660                                         break;
1661                                 }
1662                         }
1663                         if (newv != nu->pntsv && b == nu->pntsv) {
1664                                 /* delete */
1665                                 bp = nu->bp;
1666                                 bpn = newbp = (BPoint *)MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
1667                                 for (b = 0; b < nu->pntsv; b++) {
1668                                         if ((bp->f1 & flag) == 0) {
1669                                                 memcpy(bpn, bp, nu->pntsu * sizeof(BPoint));
1670                                                 keyIndex_updateBP(cu->editnurb, bp, bpn, nu->pntsu);
1671                                                 bpn += nu->pntsu;
1672                                         }
1673                                         else {
1674                                                 keyIndex_delBP(cu->editnurb, bp);
1675                                         }
1676                                         bp += nu->pntsu;
1677                                 }
1678                                 nu->pntsv = newv;
1679                                 MEM_freeN(nu->bp);
1680                                 nu->bp = newbp;
1681                                 BKE_nurb_order_clamp_v(nu);
1682
1683                                 BKE_nurb_knot_calc_v(nu);
1684                         }
1685                         else {
1686                                 /* is the nurb in V direction selected */
1687                                 newu = nu->pntsu;
1688                                 for (a = 0; a < nu->pntsu; a++) {
1689                                         bp = &nu->bp[a];
1690                                         sel = 0;
1691                                         for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
1692                                                 if (bp->f1 & flag) sel++;
1693                                         }
1694                                         if (sel == nu->pntsv) {
1695                                                 newu--;
1696                                         }
1697                                         else if (sel >= 1) {
1698                                                 /* don't delete */
1699                                                 break;
1700                                         }
1701                                 }
1702                                 if (newu != nu->pntsu && a == nu->pntsu) {
1703                                         /* delete */
1704                                         bp = nu->bp;
1705                                         bpn = newbp = (BPoint *)MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
1706                                         for (b = 0; b < nu->pntsv; b++) {
1707                                                 for (a = 0; a < nu->pntsu; a++, bp++) {
1708                                                         if ((bp->f1 & flag) == 0) {
1709                                                                 *bpn = *bp;
1710                                                                 keyIndex_updateBP(cu->editnurb, bp, bpn, 1);
1711                                                                 bpn++;
1712                                                         }
1713                                                         else {
1714                                                                 keyIndex_delBP(cu->editnurb, bp);
1715                                                         }
1716                                                 }
1717                                         }
1718                                         MEM_freeN(nu->bp);
1719                                         nu->bp = newbp;
1720                                         if (newu == 1 && nu->pntsv > 1) {    /* make a U spline */
1721                                                 nu->pntsu = nu->pntsv;
1722                                                 nu->pntsv = 1;
1723                                                 SWAP(short, nu->orderu, nu->orderv);
1724                                                 BKE_nurb_order_clamp_u(nu);
1725                                                 if (nu->knotsv) MEM_freeN(nu->knotsv);
1726                                                 nu->knotsv = NULL;
1727                                         }
1728                                         else {
1729                                                 nu->pntsu = newu;
1730                                                 BKE_nurb_order_clamp_u(nu);
1731                                         }
1732                                         BKE_nurb_knot_calc_u(nu);
1733                                 }
1734                         }
1735                 }
1736                 nu = next;
1737         }
1738
1739         if (ED_curve_updateAnimPaths(obedit->data))
1740                 WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
1741
1742         return OPERATOR_FINISHED;
1743 }
1744
1745 /* only for OB_SURF */
1746 static short extrudeflagNurb(EditNurb *editnurb, int flag)
1747 {
1748         Nurb *nu;
1749         BPoint *bp, *bpn, *newbp;
1750         int ok = 0, a, u, v, len;
1751
1752         nu = editnurb->nurbs.first;
1753         while (nu) {
1754
1755                 if (nu->pntsv == 1) {
1756                         bp = nu->bp;
1757                         a = nu->pntsu;
1758                         while (a) {
1759                                 if (bp->f1 & flag) {
1760                                         /* pass */
1761                                 }
1762                                 else {
1763                                         break;
1764                                 }
1765                                 bp++;
1766                                 a--;
1767                         }
1768                         if (a == 0) {
1769                                 ok = 1;
1770                                 newbp = (BPoint *)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
1771                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
1772                                 bp = newbp + nu->pntsu;
1773                                 ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu);
1774                                 MEM_freeN(nu->bp);
1775                                 nu->bp = newbp;
1776                                 a = nu->pntsu;
1777                                 while (a--) {
1778                                         select_bpoint(bp, SELECT, flag, HIDDEN);
1779                                         select_bpoint(newbp, DESELECT, flag, HIDDEN);
1780                                         bp++; 
1781                                         newbp++;
1782                                 }
1783
1784                                 nu->pntsv = 2;
1785                                 nu->orderv = 2;
1786                                 BKE_nurb_knot_calc_v(nu);
1787                         }
1788                 }
1789                 else {
1790                         /* which row or column is selected */
1791
1792                         if (isNurbselUV(nu, &u, &v, flag)) {
1793
1794                                 /* deselect all */
1795                                 bp = nu->bp;
1796                                 a = nu->pntsu * nu->pntsv;
1797                                 while (a--) {
1798                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
1799                                         bp++;
1800                                 }
1801
1802                                 if (u == 0 || u == nu->pntsv - 1) {      /* row in u-direction selected */
1803                                         ok = 1;
1804                                         newbp = (BPoint *)MEM_mallocN(nu->pntsu * (nu->pntsv + 1) *
1805                                                                       sizeof(BPoint), "extrudeNurb1");
1806                                         if (u == 0) {
1807                                                 len = nu->pntsv * nu->pntsu;
1808                                                 ED_curve_bpcpy(editnurb, newbp + nu->pntsu, nu->bp, len);
1809                                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
1810                                                 bp = newbp;
1811                                         }
1812                                         else {
1813                                                 len = nu->pntsv * nu->pntsu;
1814                                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, len);
1815                                                 ED_curve_bpcpy(editnurb, newbp + len, &nu->bp[len - nu->pntsu], nu->pntsu);
1816                                                 bp = newbp + len;
1817                                         }
1818
1819                                         a = nu->pntsu;
1820                                         while (a--) {
1821                                                 select_bpoint(bp, SELECT, flag, HIDDEN);
1822                                                 bp++;
1823                                         }
1824
1825                                         MEM_freeN(nu->bp);
1826                                         nu->bp = newbp;
1827                                         nu->pntsv++;
1828                                         BKE_nurb_knot_calc_v(nu);
1829                                 }
1830                                 else if (v == 0 || v == nu->pntsu - 1) {     /* column in v-direction selected */
1831                                         ok = 1;
1832                                         bpn = newbp = (BPoint *)MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
1833                                         bp = nu->bp;
1834
1835                                         for (a = 0; a < nu->pntsv; a++) {
1836                                                 if (v == 0) {
1837                                                         *bpn = *bp;
1838                                                         bpn->f1 |= flag;
1839                                                         bpn++;
1840                                                 }
1841                                                 ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu);
1842                                                 bp += nu->pntsu;
1843                                                 bpn += nu->pntsu;
1844                                                 if (v == nu->pntsu - 1) {
1845                                                         *bpn = *(bp - 1);
1846                                                         bpn->f1 |= flag;
1847                                                         bpn++;
1848                                                 }
1849                                         }
1850
1851                                         MEM_freeN(nu->bp);
1852                                         nu->bp = newbp;
1853                                         nu->pntsu++;
1854                                         BKE_nurb_knot_calc_u(nu);
1855                                 }
1856                         }
1857                 }
1858                 nu = nu->next;
1859         }
1860
1861         return ok;
1862 }
1863
1864 static void adduplicateflagNurb(Object *obedit, short flag)
1865 {
1866         ListBase *editnurb = object_editcurve_get(obedit);
1867         Nurb *nu, *newnu;
1868         BezTriple *bezt, *bezt1;
1869         BPoint *bp, *bp1;
1870         Curve *cu = (Curve *)obedit->data;
1871         int a, b, starta, enda, newu, newv;
1872         char *usel;
1873
1874         cu->lastsel = NULL;
1875
1876         nu = editnurb->last;
1877         while (nu) {
1878                 if (nu->type == CU_BEZIER) {
1879                         bezt = nu->bezt;
1880                         for (a = 0; a < nu->pntsu; a++) {
1881                                 enda = -1;
1882                                 starta = a;
1883                                 while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) {
1884                                         select_beztriple(bezt, DESELECT, flag, HIDDEN);
1885                                         enda = a;
1886                                         if (a >= nu->pntsu - 1) break;
1887                                         a++;
1888                                         bezt++;
1889                                 }
1890                                 if (enda >= starta) {
1891                                         newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN");
1892                                         memcpy(newnu, nu, sizeof(Nurb));
1893                                         BLI_addtail(editnurb, newnu);
1894                                         set_actNurb(obedit, newnu);
1895                                         newnu->pntsu = enda - starta + 1;
1896                                         newnu->bezt = (BezTriple *)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");
1897                                         memcpy(newnu->bezt, &nu->bezt[starta], newnu->pntsu * sizeof(BezTriple));
1898
1899                                         b = newnu->pntsu;
1900                                         bezt1 = newnu->bezt;
1901                                         while (b--) {
1902                                                 select_beztriple(bezt1, SELECT, flag, HIDDEN);
1903                                                 bezt1++;
1904                                         }
1905
1906                                         if (nu->flagu & CU_NURB_CYCLIC) {
1907                                                 if (starta != 0 || enda != nu->pntsu - 1) {
1908                                                         newnu->flagu &= ~CU_NURB_CYCLIC;
1909                                                 }
1910                                         }
1911                                 }
1912                                 bezt++;
1913                         }
1914                 }
1915                 else if (nu->pntsv == 1) {    /* because UV Nurb has a different method for dupli */
1916                         bp = nu->bp;
1917                         for (a = 0; a < nu->pntsu; a++) {
1918                                 enda = -1;
1919                                 starta = a;
1920                                 while (bp->f1 & flag) {
1921                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
1922                                         enda = a;
1923                                         if (a >= nu->pntsu - 1) break;
1924                                         a++;
1925                                         bp++;
1926                                 }
1927                                 if (enda >= starta) {
1928                                         newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN3");
1929                                         memcpy(newnu, nu, sizeof(Nurb));
1930                                         set_actNurb(obedit, newnu);
1931                                         BLI_addtail(editnurb, newnu);
1932                                         newnu->pntsu = enda - starta + 1;
1933                                         newnu->bp = (BPoint *)MEM_mallocN((enda - starta + 1) * sizeof(BPoint), "adduplicateN4");
1934                                         memcpy(newnu->bp, &nu->bp[starta], newnu->pntsu * sizeof(BPoint));
1935
1936                                         b = newnu->pntsu;
1937                                         bp1 = newnu->bp;
1938                                         while (b--) {
1939                                                 select_bpoint(bp1, SELECT, flag, HIDDEN);
1940                                                 bp1++;
1941                                         }
1942
1943                                         if (nu->flagu & CU_NURB_CYCLIC) {
1944                                                 if (starta != 0 || enda != nu->pntsu - 1) {
1945                                                         newnu->flagu &= ~CU_NURB_CYCLIC;
1946                                                 }
1947                                         }
1948
1949                                         /* knots */
1950                                         newnu->knotsu = NULL;
1951                                         BKE_nurb_knot_calc_u(newnu);
1952                                 }
1953                                 bp++;
1954                         }
1955                 }
1956                 else {
1957                         /* a rectangular area in nurb has to be selected */
1958                         if (isNurbsel(nu)) {
1959                                 usel = MEM_callocN(nu->pntsu, "adduplicateN4");
1960                                 bp = nu->bp;
1961                                 for (a = 0; a < nu->pntsv; a++) {
1962                                         for (b = 0; b < nu->pntsu; b++, bp++) {
1963                                                 if (bp->f1 & flag) usel[b]++;
1964                                         }
1965                                 }
1966                                 newu = 0;
1967                                 newv = 0;
1968                                 for (a = 0; a < nu->pntsu; a++) {
1969                                         if (usel[a]) {
1970                                                 if (newv == 0 || usel[a] == newv) {
1971                                                         newv = usel[a];
1972                                                         newu++;
1973                                                 }
1974                                                 else {
1975                                                         newv = 0;
1976                                                         break;
1977                                                 }
1978                                         }
1979                                 }
1980                                 if (newu == 0 || newv == 0) {
1981                                         if (G.debug & G_DEBUG)
1982                                                 printf("Can't duplicate Nurb\n");
1983                                 }
1984                                 else {
1985
1986                                         if (newu == 1) SWAP(int, newu, newv);
1987
1988                                         newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
1989                                         memcpy(newnu, nu, sizeof(Nurb));
1990                                         BLI_addtail(editnurb, newnu);
1991                                         set_actNurb(obedit, newnu);
1992                                         newnu->pntsu = newu;
1993                                         newnu->pntsv = newv;
1994                                         newnu->bp = (BPoint *)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
1995                                         BKE_nurb_order_clamp_u(newnu);
1996                                         BKE_nurb_order_clamp_v(newnu);
1997                                         
1998                                         newnu->knotsu = newnu->knotsv = NULL;
1999                                         
2000                                         bp = newnu->bp;
2001                                         bp1 = nu->bp;
2002                                         for (a = 0; a < nu->pntsv; a++) {
2003                                                 for (b = 0; b < nu->pntsu; b++, bp1++) {
2004                                                         if (bp1->f1 & flag) {
2005                                                                 memcpy(bp, bp1, sizeof(BPoint));
2006                                                                 select_bpoint(bp1, DESELECT, flag, HIDDEN);
2007                                                                 bp++;
2008                                                         }
2009                                                 }
2010                                         }
2011                                         if (BKE_nurb_check_valid_u(newnu)) {
2012                                                 if (nu->pntsu == newnu->pntsu && nu->knotsu) {
2013                                                         newnu->knotsu = MEM_dupallocN(nu->knotsu);
2014                                                 }
2015                                                 else {
2016                                                         BKE_nurb_knot_calc_u(newnu);
2017                                                 }
2018                                         }
2019                                         if (BKE_nurb_check_valid_v(newnu)) {
2020                                                 if (nu->pntsv == newnu->pntsv && nu->knotsv) {
2021                                                         newnu->knotsv = MEM_dupallocN(nu->knotsv);
2022                                                 }
2023                                                 else {
2024                                                         BKE_nurb_knot_calc_v(newnu);
2025                                                 }
2026                                         }
2027                                 }
2028                                 MEM_freeN(usel);
2029                         }
2030                 }
2031
2032                 nu = nu->prev;
2033         }
2034         
2035         /* actnu changed */
2036 }
2037
2038 /**************** switch direction operator ***************/
2039
2040 static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
2041 {
2042         Object *obedit = CTX_data_edit_object(C);
2043         Curve *cu = (Curve *)obedit->data;
2044         EditNurb *editnurb = cu->editnurb;
2045         Nurb *nu;
2046
2047         for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
2048                 if (isNurbsel(nu)) {
2049                         BKE_nurb_direction_switch(nu);
2050                         keyData_switchDirectionNurb(cu, nu);
2051                 }
2052         }
2053
2054         if (ED_curve_updateAnimPaths(obedit->data))
2055                 WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
2056
2057         DAG_id_tag_update(obedit->data, 0);
2058         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2059
2060         return OPERATOR_FINISHED;
2061 }
2062
2063 void CURVE_OT_switch_direction(wmOperatorType *ot)
2064 {
2065         /* identifiers */
2066         ot->name = "Switch Direction";
2067         ot->description = "Switch direction of selected splines";
2068         ot->idname = "CURVE_OT_switch_direction";
2069         
2070         /* api callbacks */
2071         ot->exec = switch_direction_exec;
2072         ot->poll = ED_operator_editsurfcurve;
2073
2074         /* flags */
2075         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2076 }
2077
2078 /****************** set weight operator *******************/
2079
2080 static int set_goal_weight_exec(bContext *C, wmOperator *op)
2081 {
2082         Object *obedit = CTX_data_edit_object(C);
2083         ListBase *editnurb = object_editcurve_get(obedit);
2084         Nurb *nu;
2085         BezTriple *bezt;
2086         BPoint *bp;
2087         float weight = RNA_float_get(op->ptr, "weight");
2088         int a;
2089                                 
2090         for (nu = editnurb->first; nu; nu = nu->next) {
2091                 if (nu->bezt) {
2092                         for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
2093                                 if (bezt->f2 & SELECT)
2094                                         bezt->weight = weight;
2095                         }
2096                 }
2097                 else if (nu->bp) {
2098                         for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
2099                                 if (bp->f1 & SELECT)
2100                                         bp->weight = weight;
2101                         }
2102                 }
2103         }
2104
2105         DAG_id_tag_update(obedit->data, 0);
2106         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2107
2108         return OPERATOR_FINISHED;
2109 }
2110
2111 void CURVE_OT_spline_weight_set(wmOperatorType *ot)
2112 {
2113         /* identifiers */
2114         ot->name = "Set Goal Weight";
2115         ot->description = "Set softbody goal weight for selected points";
2116         ot->idname = "CURVE_OT_spline_weight_set";
2117         
2118         /* api callbacks */
2119         ot->exec = set_goal_weight_exec;
2120         ot->invoke = WM_operator_props_popup;
2121         ot->poll = ED_operator_editsurfcurve;
2122
2123         /* flags */
2124         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2125
2126         /* properties */
2127         RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
2128 }
2129
2130 /******************* set radius operator ******************/
2131
2132 static int set_radius_exec(bContext *C, wmOperator *op)
2133 {
2134         Object *obedit = CTX_data_edit_object(C);
2135         ListBase *editnurb = object_editcurve_get(obedit);
2136         Nurb *nu;
2137         BezTriple *bezt;
2138         BPoint *bp;
2139         float radius = RNA_float_get(op->ptr, "radius");
2140         int a;
2141         
2142         for (nu = editnurb->first; nu; nu = nu->next) {
2143                 if (nu->bezt) {
2144                         for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
2145                                 if (bezt->f2 & SELECT)
2146                                         bezt->radius = radius;
2147                         }
2148                 }
2149                 else if (nu->bp) {
2150                         for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
2151                                 if (bp->f1 & SELECT)
2152                                         bp->radius = radius;
2153                         }
2154                 }
2155         }
2156
2157         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2158         DAG_id_tag_update(obedit->data, 0);
2159
2160         return OPERATOR_FINISHED;
2161 }
2162
2163 void CURVE_OT_radius_set(wmOperatorType *ot)
2164 {
2165         /* identifiers */
2166         ot->name = "Set Curve Radius";
2167         ot->description = "Set per-point radius which is used for bevel tapering";
2168         ot->idname = "CURVE_OT_radius_set";
2169         
2170         /* api callbacks */
2171         ot->exec = set_radius_exec;
2172         ot->invoke = WM_operator_props_popup;
2173         ot->poll = ED_operator_editsurfcurve;
2174
2175         /* flags */
2176         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2177
2178         /* properties */
2179         RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "", 0.0001f, 10.0f);
2180 }
2181
2182 /********************* smooth operator ********************/
2183
2184 static int smooth_exec(bContext *C, wmOperator *UNUSED(op))
2185 {
2186         Object *obedit = CTX_data_edit_object(C);
2187         ListBase *editnurb = object_editcurve_get(obedit);
2188         Nurb *nu;
2189         BezTriple *bezt, *beztOrig;
2190         BPoint *bp, *bpOrig;
2191         float val, newval, offset;
2192         int a, i, change = 0;
2193         
2194         for (nu = editnurb->first; nu; nu = nu->next) {
2195                 if (nu->bezt) {
2196                         change = 0;
2197                         beztOrig = MEM_dupallocN(nu->bezt);
2198                         for (bezt = &nu->bezt[1], a = 1; a < nu->pntsu - 1; a++, bezt++) {
2199                                 if (bezt->f2 & SELECT) {
2200                                         for (i = 0; i < 3; i++) {
2201                                                 val = bezt->vec[1][i];
2202                                                 newval = ((beztOrig + (a - 1))->vec[1][i] * 0.5f) + ((beztOrig + (a + 1))->vec[1][i] * 0.5f);
2203                                                 offset = (val * ((1.0f / 6.0f) * 5.0f)) + (newval * (1.0f / 6.0f)) - val;
2204                                                 /* offset handles */
2205                                                 bezt->vec[1][i] += offset;
2206                                                 bezt->vec[0][i] += offset;
2207                                                 bezt->vec[2][i] += offset;
2208                                         }
2209                                         change = 1;
2210                                 }
2211                         }
2212                         MEM_freeN(beztOrig);
2213                         if (change)
2214                                 BKE_nurb_handles_calc(nu);
2215                 }
2216                 else if (nu->bp) {
2217                         bpOrig = MEM_dupallocN(nu->bp);
2218                         /* Same as above, keep these the same! */
2219                         for (bp = &nu->bp[1], a = 1; a < nu->pntsu - 1; a++, bp++) {
2220                                 if (bp->f1 & SELECT) {
2221                                         for (i = 0; i < 3; i++) {
2222                                                 val = bp->vec[i];
2223                                                 newval = ((bpOrig + (a - 1))->vec[i] * 0.5f) + ((bpOrig + (a + 1))->vec[i] * 0.5f);
2224                                                 offset = (val * ((1.0f / 6.0f) * 5.0f)) + (newval * (1.0f / 6.0f)) - val;
2225                                         
2226                                                 bp->vec[i] += offset;
2227                                         }
2228                                 }
2229                         }
2230                         MEM_freeN(bpOrig);
2231                 }
2232         }
2233
2234         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2235         DAG_id_tag_update(obedit->data, 0);
2236
2237         return OPERATOR_FINISHED;
2238 }
2239
2240 void CURVE_OT_smooth(wmOperatorType *ot)
2241 {
2242         /* identifiers */
2243         ot->name = "Smooth";
2244         ot->description = "Flatten angles of selected points";
2245         ot->idname = "CURVE_OT_smooth";
2246         
2247         /* api callbacks */
2248         ot->exec = smooth_exec;
2249         ot->poll = ED_operator_editsurfcurve;
2250
2251         /* flags */
2252         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2253 }
2254
2255 /**************** smooth curve radius operator *************/
2256
2257 /* TODO, make smoothing distance based */
2258 static int smooth_radius_exec(bContext *C, wmOperator *UNUSED(op))
2259 {
2260         Object *obedit = CTX_data_edit_object(C);
2261         ListBase *editnurb = object_editcurve_get(obedit);
2262         Nurb *nu;
2263         BezTriple *bezt;
2264         BPoint *bp;
2265         int a;
2266         
2267         /* use for smoothing */
2268         int last_sel;
2269         int start_sel, end_sel; /* selection indices, inclusive */
2270         float start_rad, end_rad, fac, range;
2271         
2272         for (nu = editnurb->first; nu; nu = nu->next) {
2273                 if (nu->bezt) {
2274                         
2275                         for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
2276                                 /* loop over selection segments of a curve, smooth each */
2277                                 
2278                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
2279                                 start_sel = -1;
2280                                 for (bezt = &nu->bezt[last_sel], a = last_sel; a < nu->pntsu; a++, bezt++) {
2281                                         if (bezt->f2 & SELECT) {
2282                                                 start_sel = a;
2283                                                 break;
2284                                         }
2285                                 }
2286                                 /* in case there are no other selected verts */
2287                                 end_sel = start_sel;
2288                                 for (bezt = &nu->bezt[start_sel + 1], a = start_sel + 1; a < nu->pntsu; a++, bezt++) {
2289                                         if ((bezt->f2 & SELECT) == 0) {
2290                                                 break;
2291                                         }
2292                                         end_sel = a;
2293                                 }
2294                                 
2295                                 if (start_sel == -1) {
2296                                         last_sel = nu->pntsu; /* next... */
2297                                 }
2298                                 else {
2299                                         last_sel = end_sel; /* before we modify it */
2300                                         
2301                                         /* now blend between start and end sel */
2302                                         start_rad = end_rad = -1.0;
2303                                         
2304                                         if (start_sel == end_sel) {
2305                                                 /* simple, only 1 point selected */
2306                                                 if (start_sel > 0)                         start_rad = nu->bezt[start_sel - 1].radius;
2307                                                 if (end_sel != -1 && end_sel < nu->pntsu)  end_rad   = nu->bezt[start_sel + 1].radius;
2308                                                 
2309                                                 if      (start_rad >= 0.0f && end_rad >= 0.0f)  nu->bezt[start_sel].radius = (start_rad + end_rad) / 2.0f;
2310                                                 else if (start_rad >= 0.0f)                     nu->bezt[start_sel].radius = start_rad;
2311                                                 else if (end_rad >= 0.0f)                       nu->bezt[start_sel].radius = end_rad;
2312                                         }
2313                                         else {
2314                                                 /* if endpoints selected, then use them */
2315                                                 if (start_sel == 0) {
2316                                                         start_rad = nu->bezt[start_sel].radius;
2317                                                         start_sel++; /* we don't want to edit the selected endpoint */
2318                                                 }
2319                                                 else {
2320                                                         start_rad = nu->bezt[start_sel - 1].radius;
2321                                                 }
2322                                                 if (end_sel == nu->pntsu - 1) {
2323                                                         end_rad = nu->bezt[end_sel].radius;
2324                                                         end_sel--; /* we don't want to edit the selected endpoint */
2325                                                 }
2326                                                 else {
2327                                                         end_rad = nu->bezt[end_sel + 1].radius;
2328                                                 }
2329                                                 
2330                                                 /* Now Blend between the points */
2331                                                 range = (float)(end_sel - start_sel) + 2.0f;
2332                                                 for (bezt = &nu->bezt[start_sel], a = start_sel; a <= end_sel; a++, bezt++) {
2333                                                         fac = (float)(1 + a - start_sel) / range;
2334                                                         bezt->radius = start_rad * (1.0f - fac) + end_rad * fac;
2335                                                 }
2336                                         }
2337                                 }
2338                         }
2339                 }
2340                 else if (nu->bp) {
2341                         /* Same as above, keep these the same! */
2342                         for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
2343                                 /* loop over selection segments of a curve, smooth each */
2344                                 
2345                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
2346                                 start_sel = -1;
2347                                 for (bp = &nu->bp[last_sel], a = last_sel; a < nu->pntsu; a++, bp++) {
2348                                         if (bp->f1 & SELECT) {
2349                                                 start_sel = a;
2350                                                 break;
2351                                         }
2352                                 }
2353                                 /* in case there are no other selected verts */
2354                                 end_sel = start_sel;
2355                                 for (bp = &nu->bp[start_sel + 1], a = start_sel + 1; a < nu->pntsu; a++, bp++) {
2356                                         if ((bp->f1 & SELECT) == 0) {
2357                                                 break;
2358                                         }
2359                                         end_sel = a;
2360                                 }
2361                                 
2362                                 if (start_sel == -1) {
2363                                         last_sel = nu->pntsu; /* next... */
2364                                 }
2365                                 else {
2366                                         last_sel = end_sel; /* before we modify it */
2367                                         
2368                                         /* now blend between start and end sel */
2369                                         start_rad = end_rad = -1.0;
2370                                         
2371                                         if (start_sel == end_sel) {
2372                                                 /* simple, only 1 point selected */
2373                                                 if (start_sel > 0) start_rad = nu->bp[start_sel - 1].radius;
2374                                                 if (end_sel != -1 && end_sel < nu->pntsu) end_rad = nu->bp[start_sel + 1].radius;
2375                                                 
2376                                                 if      (start_rad >= 0.0f && end_rad >= 0.0f)  nu->bp[start_sel].radius = (start_rad + end_rad) / 2;
2377                                                 else if (start_rad >= 0.0f)                     nu->bp[start_sel].radius = start_rad;
2378                                                 else if (end_rad >= 0.0f)                       nu->bp[start_sel].radius = end_rad;
2379                                         }
2380                                         else {
2381                                                 /* if endpoints selected, then use them */
2382                                                 if (start_sel == 0) {
2383                                                         start_rad = nu->bp[start_sel].radius;
2384                                                         start_sel++; /* we don't want to edit the selected endpoint */
2385                                                 }
2386                                                 else {
2387                                                         start_rad = nu->bp[start_sel - 1].radius;
2388                                                 }
2389                                                 if (end_sel == nu->pntsu - 1) {
2390                                                         end_rad = nu->bp[end_sel].radius;
2391                                                         end_sel--; /* we don't want to edit the selected endpoint */
2392                                                 }
2393                                                 else {
2394                                                         end_rad = nu->bp[end_sel + 1].radius;
2395                                                 }
2396                                                 
2397                                                 /* Now Blend between the points */
2398                                                 range = (float)(end_sel - start_sel) + 2.0f;
2399                                                 for (bp = &nu->bp[start_sel], a = start_sel; a <= end_sel; a++, bp++) {
2400                                                         fac = (float)(1 + a - start_sel) / range;
2401                                                         bp->radius = start_rad * (1.0f - fac) + end_rad * fac;
2402                                                 }
2403                                         }
2404                                 }
2405                         }
2406                 }
2407         }
2408
2409         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2410         DAG_id_tag_update(obedit->data, 0);
2411
2412         return OPERATOR_FINISHED;
2413 }
2414
2415 void CURVE_OT_smooth_radius(wmOperatorType *ot)
2416 {
2417         /* identifiers */
2418         ot->name = "Smooth Curve Radius";
2419         ot->description = "Flatten radii of selected points";
2420         ot->idname = "CURVE_OT_smooth_radius";
2421         
2422         /* api clastbacks */
2423         ot->exec = smooth_radius_exec;
2424         ot->poll = ED_operator_editsurfcurve;
2425         
2426         /* flags */
2427         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2428 }
2429
2430 /***************** selection utility *************************/
2431
2432 /* next == 1 -> select next         */
2433 /* next == -1 -> select previous    */
2434 /* cont == 1 -> select continuously */
2435 /* selstatus, inverts behavior          */
2436 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus)
2437 {
2438         Nurb *nu;
2439         BezTriple *bezt;
2440         BPoint *bp;
2441         int a;
2442         short lastsel = false;
2443         
2444         if (next == 0) return;
2445         
2446         for (nu = editnurb->first; nu; nu = nu->next) {
2447                 lastsel = false;
2448                 if (nu->type == CU_BEZIER) {
2449                         a = nu->pntsu;
2450                         bezt = nu->bezt;
2451                         if (next < 0) bezt = &nu->bezt[a - 1];
2452                         while (a--) {
2453                                 if (a - abs(next) < 0) break;
2454                                 if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == 0))) {
2455                                         bezt += next;
2456                                         if (!(bezt->f2 & SELECT) || (selstatus == 0)) {
2457                                                 short sel = select_beztriple(bezt, selstatus, 1, VISIBLE);
2458                                                 if ((sel == 1) && (cont == 0)) lastsel = true;
2459                                         }
2460                                 }
2461                                 else {
2462                                         bezt += next;
2463                                         lastsel = false;
2464                                 }
2465                                 /* move around in zigzag way so that we go through each */
2466                                 bezt -= (next - next / abs(next));
2467                         }
2468                 }
2469                 else {
2470                         a = nu->pntsu * nu->pntsv;
2471                         bp = nu->bp;
2472                         if (next < 0) bp = &nu->bp[a - 1];
2473                         while (a--) {
2474                                 if (a - abs(next) < 0) break;
2475                                 if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == 0))) {
2476                                         bp += next;
2477                                         if (!(bp->f1 & SELECT) || (selstatus == 0)) {
2478                                                 short sel = select_bpoint(bp, selstatus, 1, VISIBLE);
2479                                                 if ((sel == 1) && (cont == 0)) lastsel = true;
2480                                         }
2481                                 }
2482                                 else {
2483                                         bp += next;
2484                                         lastsel = false;
2485                                 }
2486                                 /* move around in zigzag way so that we go through each */
2487                                 bp -= (next - next / abs(next));
2488                         }
2489                 }
2490         }
2491 }
2492
2493 /**************** select start/end operators **************/
2494
2495 /* (de)selects first or last of visible part of each Nurb depending on selFirst
2496  * selFirst: defines the end of which to select
2497  * doswap: defines if selection state of each first/last control point is swapped
2498  * selstatus: selection status in case doswap is false
2499  */
2500 void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus)
2501 {
2502         ListBase *editnurb = object_editcurve_get(obedit);
2503         Nurb *nu;
2504         BPoint *bp;
2505         BezTriple *bezt;
2506         Curve *cu;
2507         int a;
2508
2509         if (obedit == NULL) return;
2510
2511         cu = (Curve *)obedit->data;
2512         cu->lastsel = NULL;
2513
2514         for (nu = editnurb->first; nu; nu = nu->next) {
2515                 if (nu->type == CU_BEZIER) {
2516                         a = nu->pntsu;
2517                         
2518                         /* which point? */
2519                         if (selfirst == 0) { /* select last */
2520                                 bezt = &nu->bezt[a - 1];
2521                         }
2522                         else { /* select first */
2523                                 bezt = nu->bezt;
2524                         }
2525                         
2526                         while (a--) {
2527                                 short sel;
2528                                 if (doswap) sel = swap_selection_beztriple(bezt);
2529                                 else sel = select_beztriple(bezt, selstatus, 1, VISIBLE);
2530                                 
2531                                 if (sel == 1) break;
2532                         }
2533                 }
2534                 else {
2535                         a = nu->pntsu * nu->pntsv;
2536                         
2537                         /* which point? */
2538                         if (selfirst == 0) { /* select last */
2539                                 bp = &nu->bp[a - 1];
2540                         }
2541                         else { /* select first */
2542                                 bp = nu->bp;
2543                         }
2544
2545                         while (a--) {
2546                                 if (bp->hide == 0) {
2547                                         short sel;
2548                                         if (doswap) sel = swap_selection_bpoint(bp);
2549                                         else sel = select_bpoint(bp, selstatus, 1, VISIBLE);
2550                                         
2551                                         if (sel == 1) break;
2552                                 }
2553                         }
2554                 }
2555         }
2556 }
2557
2558 static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
2559 {
2560         Object *obedit = CTX_data_edit_object(C);
2561
2562         selectend_nurb(obedit, FIRST, 1, DESELECT);
2563         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2564
2565         return OPERATOR_FINISHED;
2566 }
2567
2568 void CURVE_OT_de_select_first(wmOperatorType *ot)
2569 {
2570         /* identifiers */
2571         ot->name = "(De)select First";
2572         ot->idname = "CURVE_OT_de_select_first";
2573         ot->description = "(De)select first of visible part of each NURBS";
2574         
2575         /* api cfirstbacks */
2576         ot->exec = de_select_first_exec;
2577         ot->poll = ED_operator_editcurve;
2578         
2579         /* flags */
2580         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2581 }
2582
2583 static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
2584 {
2585         Object *obedit = CTX_data_edit_object(C);
2586
2587         selectend_nurb(obedit, LAST, 1, DESELECT);
2588         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2589
2590         return OPERATOR_FINISHED;
2591 }
2592
2593 void CURVE_OT_de_select_last(wmOperatorType *ot)
2594 {
2595         /* identifiers */
2596         ot->name = "(De)select Last";
2597         ot->idname = "CURVE_OT_de_select_last";
2598         ot->description = "(De)select last of visible part of each NURBS";
2599         
2600         /* api clastbacks */
2601         ot->exec = de_select_last_exec;
2602         ot->poll = ED_operator_editcurve;
2603         
2604         /* flags */
2605         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2606 }
2607
2608 /******************* de select all operator ***************/
2609
2610 static short nurb_has_selected_cps(ListBase *editnurb)
2611 {
2612         Nurb *nu;
2613         BezTriple *bezt;
2614         BPoint *bp;
2615         int a;
2616
2617         for (nu = editnurb->first; nu; nu = nu->next) {
2618                 if (nu->type == CU_BEZIER) {
2619                         a = nu->pntsu;
2620                         bezt = nu->bezt;
2621                         while (a--) {
2622                                 if (bezt->hide == 0) {
2623                                         if ((bezt->f1 & SELECT) ||
2624                                             (bezt->f2 & SELECT) ||
2625                                             (bezt->f3 & SELECT))
2626                                         {
2627                                                 return 1;
2628                                         }
2629                                 }
2630                                 bezt++;
2631                         }
2632                 }
2633                 else {
2634                         a = nu->pntsu * nu->pntsv;
2635                         bp = nu->bp;
2636                         while (a--) {
2637                                 if ((bp->hide == 0) && (bp->f1 & SELECT)) return 1;
2638                                 bp++;
2639                         }
2640                 }
2641         }
2642         
2643         return 0;
2644 }
2645
2646 static int de_select_all_exec(bContext *C, wmOperator *op)
2647 {
2648         Object *obedit = CTX_data_edit_object(C);
2649         ListBase *editnurb = object_editcurve_get(obedit);
2650         int action = RNA_enum_get(op->ptr, "action");
2651
2652         if (action == SEL_TOGGLE) {
2653                 action = SEL_SELECT;
2654                 if (nurb_has_selected_cps(editnurb))
2655                         action = SEL_DESELECT;
2656         }
2657
2658         switch (action) {
2659                 case SEL_SELECT:
2660                         CU_select_all(obedit);
2661                         break;
2662                 case SEL_DESELECT:
2663                         CU_deselect_all(obedit);
2664                         break;
2665                 case SEL_INVERT:
2666                         CU_select_swap(obedit);
2667                         break;
2668         }
2669         
2670         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2671
2672         return OPERATOR_FINISHED;
2673 }
2674
2675 void CURVE_OT_select_all(wmOperatorType *ot)
2676 {
2677         /* identifiers */
2678         ot->name = "(De)select All";
2679         ot->idname = "CURVE_OT_select_all";
2680         ot->description = "(De)select all control points";
2681         
2682         /* api callbacks */
2683         ot->exec = de_select_all_exec;
2684         ot->poll = ED_operator_editsurfcurve;
2685         
2686         /* flags */
2687         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2688
2689         /* properties */
2690         WM_operator_properties_select_all(ot);
2691 }
2692
2693 /********************** hide operator *********************/
2694
2695 static int hide_exec(bContext *C, wmOperator *op)
2696 {
2697         Object *obedit = CTX_data_edit_object(C);
2698         Curve *cu = obedit->data;
2699         ListBase *editnurb = object_editcurve_get(obedit);
2700         Nurb *nu;
2701         BPoint *bp;
2702         BezTriple *bezt;
2703         int a, sel, invert = RNA_boolean_get(op->ptr, "unselected");
2704
2705         for (nu = editnurb->first; nu; nu = nu->next) {
2706                 if (nu->type == CU_BEZIER) {
2707                         bezt = nu->bezt;
2708                         a = nu->pntsu;
2709                         sel = 0;
2710                         while (a--) {
2711                                 if (invert == 0 && BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
2712                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
2713                                         bezt->hide = 1;
2714                                 }
2715                                 else if (invert && !BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
2716                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
2717                                         bezt->hide = 1;
2718                                 }
2719                                 if (bezt->hide) sel++;
2720                                 bezt++;
2721                         }
2722                         if (sel == nu->pntsu) nu->hide = 1;
2723                 }
2724                 else {
2725                         bp = nu->bp;
2726                         a = nu->pntsu * nu->pntsv;
2727                         sel = 0;
2728                         while (a--) {
2729                                 if (invert == 0 && (bp->f1 & SELECT)) {
2730                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
2731                                         bp->hide = 1;
2732                                 }
2733                                 else if (invert && (bp->f1 & SELECT) == 0) {
2734                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
2735                                         bp->hide = 1;
2736                                 }
2737                                 if (bp->hide) sel++;
2738                                 bp++;
2739                         }
2740                         if (sel == nu->pntsu * nu->pntsv) nu->hide = 1;
2741                 }
2742         }
2743
2744         DAG_id_tag_update(obedit->data, 0);
2745         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2746
2747         return OPERATOR_FINISHED;
2748 }
2749
2750 void CURVE_OT_hide(wmOperatorType *ot)
2751 {
2752         /* identifiers */
2753         ot->name = "Hide Selected";
2754         ot->idname = "CURVE_OT_hide";
2755         ot->description = "Hide (un)selected control points";
2756         
2757         /* api callbacks */
2758         ot->exec = hide_exec;
2759         ot->poll = ED_operator_editsurfcurve;
2760         
2761         /* flags */
2762         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2763         
2764         /* props */
2765         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
2766 }
2767
2768 /********************** reveal operator *********************/
2769
2770 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
2771 {
2772         Object *obedit = CTX_data_edit_object(C);
2773         ListBase *editnurb = object_editcurve_get(obedit);
2774         Nurb *nu;
2775         BPoint *bp;
2776         BezTriple *bezt;
2777         int a;
2778
2779         for (nu = editnurb->first; nu; nu = nu->next) {
2780                 nu->hide = 0;
2781                 if (nu->type == CU_BEZIER) {
2782                         bezt = nu->bezt;
2783                         a = nu->pntsu;
2784                         while (a--) {
2785                                 if (bezt->hide) {
2786                                         select_beztriple(bezt, SELECT, 1, HIDDEN);
2787                                         bezt->hide = 0;
2788                                 }
2789                                 bezt++;
2790                         }
2791                 }
2792                 else {
2793                         bp = nu->bp;
2794                         a = nu->pntsu * nu->pntsv;
2795                         while (a--) {
2796                                 if (bp->hide) {
2797                                         select_bpoint(bp, SELECT, 1, HIDDEN);
2798                                         bp->hide = 0;
2799                                 }
2800                                 bp++;
2801                         }
2802                 }
2803         }
2804
2805         DAG_id_tag_update(obedit->data, 0);
2806         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2807
2808         return OPERATOR_FINISHED;
2809 }
2810
2811 void CURVE_OT_reveal(wmOperatorType *ot)
2812 {
2813         /* identifiers */
2814         ot->name = "Reveal Hidden";
2815         ot->idname = "CURVE_OT_reveal";
2816         ot->description = "Show again hidden control points";
2817         
2818         /* api callbacks */
2819         ot->exec = reveal_exec;
2820         ot->poll = ED_operator_editsurfcurve;
2821         
2822         /* flags */
2823         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2824 }
2825
2826 /********************** subdivide operator *********************/
2827
2828 /** Divide the line segments associated with the currently selected
2829  * curve nodes (Bezier or NURB). If there are no valid segment
2830  * selections within the current selection, nothing happens.
2831  */
2832 static void subdividenurb(Object *obedit, int number_cuts)
2833 {
2834         Curve *cu = obedit->data;
2835         EditNurb *editnurb = cu->editnurb;
2836         Nurb *nu;
2837         BezTriple *prevbezt, *bezt, *beztnew, *beztn;
2838         BPoint *bp, *prevbp, *bpnew, *bpn;
2839         float vec[15];
2840         int a, b, sel, amount, *usel, *vsel, i;
2841         float factor;
2842
2843         // printf("*** subdivideNurb: entering subdivide\n");
2844
2845         for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
2846                 amount = 0;
2847                 if (nu->type == CU_BEZIER) {
2848                         /*
2849                          * Insert a point into a 2D Bezier curve.
2850                          * Endpoints are preserved. Otherwise, all selected and inserted points are
2851                          * newly created. Old points are discarded.
2852                          */