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