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