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