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