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