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