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