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