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