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