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