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