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