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