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