70cd8333e8fb47a9500b63e3df1da365cc6fd231
[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                                                                 }
780                                                                 ofs[i++][0]= bezt->alfa - oldbezt->alfa;
781                                                         } else {
782                                                                 i += 4;
783                                                         }
784                                                         bezt++;
785                                                 }
786                                         }
787                                         else {
788                                                 bp= nu->bp;
789                                                 a= nu->pntsu*nu->pntsv;
790                                                 while(a--) {
791                                                         oldbp= getKeyIndexOrig_bp(editnurb, bp);
792                                                         if (oldbp) {
793                                                                 VECSUB(ofs[i], bp->vec, oldbp->vec);
794                                                                 ofs[i+1][0]= bp->alfa - oldbp->alfa;
795                                                         }
796                                                         i += 2;
797                                                         ++bp;
798                                                 }
799                                         }
800
801                                         nu= nu->next;
802                                 }
803                         }
804                 }
805
806                 currkey = cu->key->block.first;
807                 while(currkey) {
808                         int apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr-1 == currkey->relative));
809
810                         float *fp= newkey= MEM_callocN(cu->key->elemsize * totvert,  "currkey->data");
811                         ofp= oldkey = currkey->data;
812
813                         nu= editnurb->nurbs.first;
814                         i = 0;
815                         while(nu) {
816                                 if(currkey == actkey) {
817                                         int restore= actkey != cu->key->refkey;
818
819                                         if(nu->bezt) {
820                                                 bezt= nu->bezt;
821                                                 a= nu->pntsu;
822                                                 while(a--) {
823                                                         oldbezt= getKeyIndexOrig_bezt(editnurb, bezt);
824
825                                                         for (j= 0; j < 3; ++j, ++i) {
826                                                                 VECCOPY(fp, bezt->vec[j]);
827
828                                                                 if (restore && oldbezt) {
829                                                                         VECCOPY(bezt->vec[j], oldbezt->vec[j]);
830                                                                 }
831
832                                                                 fp+= 3;
833                                                         }
834                                                         fp[0]= bezt->alfa;
835
836                                                         if(restore && oldbezt) {
837                                                                 bezt->alfa= oldbezt->alfa;
838                                                         }
839
840                                                         fp+= 3; ++i;/* alphas */
841                                                         ++bezt;
842                                                 }
843                                         }
844                                         else {
845                                                 bp= nu->bp;
846                                                 a= nu->pntsu*nu->pntsv;
847                                                 while(a--) {
848                                                         oldbp= getKeyIndexOrig_bp(editnurb, bp);
849
850                                                         VECCOPY(fp, bp->vec);
851
852                                                         fp[3]= bp->alfa;
853
854                                                         if(restore && oldbp) {
855                                                                 VECCOPY(bp->vec, oldbp->vec);
856                                                                 bp->alfa= oldbp->alfa;
857                                                         }
858
859                                                         fp+= 4;
860                                                         ++bp;
861                                                         i+=2;
862                                                 }
863                                         }
864                                 }
865                                 else {
866                                         int index;
867                                         float *curofp;
868
869                                         if(oldkey) {
870                                                 if(nu->bezt) {
871                                                         bezt= nu->bezt;
872                                                         a= nu->pntsu;
873
874                                                         while(a--) {
875                                                                 index= getKeyIndexOrig_index(editnurb, bezt);
876                                                                 if (index >= 0) {
877                                                                         curofp= ofp + index;
878
879                                                                         for (j= 0; j < 3; ++j, ++i) {
880                                                                                 VECCOPY(fp, curofp);
881
882                                                                                 if(apply_offset) {
883                                                                                         VECADD(fp, fp, ofs[i]);
884                                                                                 }
885
886                                                                                 fp+= 3; curofp+= 3;
887                                                                         }
888                                                                         fp[0]= curofp[0];
889
890                                                                         if(apply_offset) {
891                                                                                 /* apply alfa offsets */
892                                                                                 VECADD(fp, fp, ofs[i]);
893                                                                                 ++i;
894                                                                         }
895
896                                                                         fp+= 3; curofp+= 3;     /* alphas */
897                                                                 } else {
898                                                                         for (j= 0; j < 3; ++j, ++i) {
899                                                                                 VECCOPY(fp, bezt->vec[j]);
900                                                                                 fp+= 3;
901                                                                         }
902                                                                         fp[0]= bezt->alfa;
903
904                                                                         fp+= 3; /* alphas */
905                                                                 }
906                                                                 ++bezt;
907                                                         }
908                                                 }
909                                                 else {
910                                                         bp= nu->bp;
911                                                         a= nu->pntsu*nu->pntsv;
912                                                         while(a--) {
913                                                                 index= getKeyIndexOrig_index(editnurb, bp);
914
915                                                                 if (index >= 0) {
916                                                                         curofp= ofp + index;
917                                                                         VECCOPY(fp, curofp);
918                                                                         fp[3]= curofp[3];
919
920                                                                         if(apply_offset) {
921                                                                                 VECADD(fp, fp, ofs[i]);
922                                                                                 fp[3]+=ofs[i+1][0];
923                                                                         }
924                                                                 } else {
925                                                                         VECCOPY(fp, bp->vec);
926                                                                         fp[3]= bp->alfa;
927                                                                 }
928
929                                                                 fp+= 4;
930                                                                 ++bp;
931                                                                 i+=2;
932                                                         }
933                                                 }
934                                         }
935                                 }
936
937                                 nu= nu->next;
938                         }
939
940                         if (apply_offset) {
941                                 /* handles could become malicious after offsets applying */
942                                 calc_keyHandles(&editnurb->nurbs, newkey);
943                         }
944
945                         currkey->totelem= totvert;
946                         if(currkey->data) MEM_freeN(currkey->data);
947                         currkey->data = newkey;
948
949                         currkey= currkey->next;
950                 }
951
952                 if(ofs) MEM_freeN(ofs);
953         }
954 }
955
956 /* ********************* LOAD and MAKE *************** */
957
958 /* load editNurb in object */
959 void load_editNurb(Object *obedit)
960 {
961         ListBase *editnurb= curve_get_editcurve(obedit);
962
963         if(obedit==NULL) return;
964
965         set_actNurb(obedit, NULL);
966
967         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
968                 Curve *cu= obedit->data;
969                 Nurb *nu, *newnu;
970                 ListBase newnurb= {NULL, NULL}, oldnurb= cu->nurb;
971
972                 for(nu= editnurb->first; nu; nu= nu->next) {
973                         newnu= duplicateNurb(nu);
974                         BLI_addtail(&newnurb, newnu);
975
976                         if(nu->type == CU_NURBS) {
977                                 clamp_nurb_order_u(nu);
978                         }
979                 }
980
981                 cu->nurb= newnurb;
982
983                 calc_shapeKeys(obedit);
984
985                 freeNurblist(&oldnurb);
986         }
987
988         set_actNurb(obedit, NULL);
989 }
990
991 /* make copy in cu->editnurb */
992 void make_editNurb(Object *obedit)
993 {
994         Curve *cu= (Curve*)obedit->data;
995         EditNurb *editnurb= cu->editnurb;
996         Nurb *nu, *newnu, *nu_act= NULL;
997         KeyBlock *actkey;
998
999         if(obedit==NULL) return;
1000
1001         set_actNurb(obedit, NULL);
1002
1003         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1004                 actkey = ob_get_keyblock(obedit);
1005                 if(actkey) {
1006                         // XXX strcpy(G.editModeTitleExtra, "(Key) ");
1007                         undo_editmode_clear();
1008                         key_to_curve(actkey, cu, &cu->nurb);
1009                 }
1010
1011                 if(editnurb) {
1012                         freeNurblist(&editnurb->nurbs);
1013                         free_editNurb_keyIndex(editnurb);
1014                         editnurb->keyindex= NULL;
1015                 } else {
1016                         editnurb= MEM_callocN(sizeof(EditNurb), "editnurb");
1017                         cu->editnurb= editnurb;
1018                 }
1019
1020                 nu= cu->nurb.first;
1021                 cu->lastsel= NULL;   /* for select row */
1022
1023                 while(nu) {
1024                         newnu= duplicateNurb(nu);
1025                         test2DNurb(newnu);      // after join, or any other creation of curve
1026                         BLI_addtail(&editnurb->nurbs, newnu);
1027
1028                         if (nu_act == NULL && isNurbsel(nu)) {
1029                                 nu_act= newnu;
1030                                 set_actNurb(obedit, newnu);
1031                         }
1032
1033                         nu= nu->next;
1034                 }
1035
1036                 if(actkey) {
1037                         editnurb->shapenr= obedit->shapenr;
1038                         init_editNurb_keyIndex(editnurb, &cu->nurb);
1039                 }
1040         }
1041 }
1042
1043 void free_curve_editNurb (Curve *cu)
1044 {
1045         if(cu->editnurb) {
1046                 freeNurblist(&cu->editnurb->nurbs);
1047                 free_editNurb_keyIndex(cu->editnurb);
1048                 MEM_freeN(cu->editnurb);
1049                 cu->editnurb= NULL;
1050         }
1051 }
1052
1053 void free_editNurb(Object *obedit)
1054 {
1055         Curve *cu= obedit->data;
1056
1057         free_curve_editNurb(cu);
1058 }
1059
1060 void CU_deselect_all(Object *obedit)
1061 {
1062         ListBase *editnurb= curve_get_editcurve(obedit);
1063
1064         if (editnurb) {
1065                 selectend_nurb(obedit, FIRST, 0, DESELECT); /* set first control points as unselected */
1066                 select_adjacent_cp(editnurb, 1, 1, DESELECT); /* cascade selection */
1067         }
1068 }
1069
1070 void CU_select_all(Object *obedit)
1071 {
1072         ListBase *editnurb= curve_get_editcurve(obedit);
1073
1074         if (editnurb) {
1075                 selectend_nurb(obedit, FIRST, 0, SELECT); /* set first control points as unselected */
1076                 select_adjacent_cp(editnurb, 1, 1, SELECT); /* cascade selection */
1077         }
1078 }
1079
1080 void CU_select_swap(Object *obedit)
1081 {
1082         ListBase *editnurb= curve_get_editcurve(obedit);
1083
1084         if (editnurb) {
1085                 Curve *cu= obedit->data;
1086                 Nurb *nu;
1087                 BPoint *bp;
1088                 BezTriple *bezt;
1089                 int a;
1090
1091                 cu->lastsel= NULL;
1092
1093                 for(nu= editnurb->first; nu; nu= nu->next) {
1094                         if(nu->type == CU_BEZIER) {
1095                                 bezt= nu->bezt;
1096                                 a= nu->pntsu;
1097                                 while(a--) {
1098                                         if(bezt->hide==0) {
1099                                                 bezt->f2 ^= SELECT; /* always do the center point */
1100                                                 if((cu->drawflag & CU_HIDE_HANDLES)==0) {
1101                                                         bezt->f1 ^= SELECT;
1102                                                         bezt->f3 ^= SELECT;
1103                                                 }
1104                                         }
1105                                         bezt++;
1106                                 }
1107                         }
1108                         else {
1109                                 bp= nu->bp;
1110                                 a= nu->pntsu*nu->pntsv;
1111                                 while(a--) {
1112                                         swap_selection_bpoint(bp);
1113                                         bp++;
1114                                 }
1115                         }
1116                 }
1117         }
1118 }
1119
1120 /******************** separate operator ***********************/
1121
1122 static int separate_exec(bContext *C, wmOperator *op)
1123 {
1124         Main *bmain= CTX_data_main(C);
1125         Scene *scene= CTX_data_scene(C);
1126         Nurb *nu, *nu1;
1127         Object *oldob, *newob;
1128         Base *oldbase, *newbase;
1129         Curve *oldcu, *newcu;
1130         EditNurb *oldedit, *newedit;
1131
1132         oldbase= CTX_data_active_base(C);
1133         oldob= oldbase->object;
1134         oldcu= oldob->data;
1135         oldedit= oldcu->editnurb;
1136
1137         if(oldcu->key) {
1138                 BKE_report(op->reports, RPT_ERROR, "Can't separate a curve with vertex keys.");
1139                 return OPERATOR_CANCELLED;
1140         }
1141
1142         WM_cursor_wait(1);
1143         
1144         /* 1. duplicate the object and data */
1145         newbase= ED_object_add_duplicate(bmain, scene, oldbase, 0);     /* 0 = fully linked */
1146         ED_base_object_select(newbase, BA_DESELECT);
1147         newob= newbase->object;
1148
1149         newcu= newob->data= copy_curve(oldcu);
1150         newcu->editnurb= NULL;
1151         oldcu->id.us--; /* because new curve is a copy: reduce user count */
1152
1153         /* 2. put new object in editmode and clear it */
1154         make_editNurb(newob);
1155         newedit= newcu->editnurb;
1156         freeNurblist(&newedit->nurbs);
1157         free_editNurb_keyIndex(newedit);
1158
1159         /* 3. move over parts from old object */
1160         for(nu= oldedit->nurbs.first; nu; nu=nu1) {
1161                 nu1= nu->next;
1162
1163                 if(isNurbsel(nu)) {
1164                         BLI_remlink(&oldedit->nurbs, nu);
1165                         BLI_addtail(&newedit->nurbs, nu);
1166                 }
1167         }
1168
1169         /* 4. put old object out of editmode */
1170         load_editNurb(newob);
1171         free_editNurb(newob);
1172
1173         DAG_id_flush_update(&oldob->id, OB_RECALC_DATA);        /* this is the original one */
1174         DAG_id_flush_update(&newob->id, OB_RECALC_DATA);        /* this is the separated one */
1175
1176         WM_event_add_notifier(C, NC_GEOM|ND_DATA, oldob->data);
1177
1178         WM_cursor_wait(0);
1179
1180         return OPERATOR_FINISHED;
1181 }
1182
1183 void CURVE_OT_separate(wmOperatorType *ot)
1184 {
1185         /* identifiers */
1186         ot->name= "Separate";
1187         ot->idname= "CURVE_OT_separate";
1188         
1189         /* api callbacks */
1190         ot->exec= separate_exec;
1191         ot->poll= ED_operator_editsurfcurve;
1192         
1193         /* flags */
1194         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1195 }
1196
1197 /* ******************* FLAGS ********************* */
1198
1199 static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
1200 {
1201         /* return u!=-1:     1 row in u-direction selected. U has value between 0-pntsv 
1202          * return v!=-1: 1 collumn in v-direction selected. V has value between 0-pntsu 
1203          */
1204         BPoint *bp;
1205         int a, b, sel;
1206
1207         *u= *v= -1;
1208
1209         bp= nu->bp;
1210         for(b=0; b<nu->pntsv; b++) {
1211                 sel= 0;
1212                 for(a=0; a<nu->pntsu; a++, bp++) {
1213                         if(bp->f1 & flag) sel++;
1214                 }
1215                 if(sel==nu->pntsu) {
1216                         if(*u== -1) *u= b;
1217                         else return 0;
1218                 }
1219                 else if(sel>1) return 0;    /* because sel==1 is still ok */
1220         }
1221
1222         for(a=0; a<nu->pntsu; a++) {
1223                 sel= 0;
1224                 bp= nu->bp+a;
1225                 for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
1226                         if(bp->f1 & flag) sel++;
1227                 }
1228                 if(sel==nu->pntsv) {
1229                         if(*v== -1) *v= a;
1230                         else return 0;
1231                 }
1232                 else if(sel>1) return 0;
1233         }
1234
1235         if(*u==-1 && *v>-1) return 1;
1236         if(*v==-1 && *u>-1) return 1;
1237         return 0;
1238 }
1239
1240 static void setflagsNurb(ListBase *editnurb, short flag)
1241 {
1242         Nurb *nu;
1243         BezTriple *bezt;
1244         BPoint *bp;
1245         int a;
1246
1247         for(nu= editnurb->first; nu; nu= nu->next) {
1248                 if(nu->type == CU_BEZIER) {
1249                         a= nu->pntsu;
1250                         bezt= nu->bezt;
1251                         while(a--) {
1252                                 bezt->f1= bezt->f2= bezt->f3= flag;
1253                                 bezt++;
1254                         }
1255                 }
1256                 else {
1257                         a= nu->pntsu*nu->pntsv;
1258                         bp= nu->bp;
1259                         while(a--) {
1260                                 bp->f1= flag;
1261                                 bp++;
1262                         }
1263                 }
1264         }
1265 }
1266
1267 static void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float rotmat[][3])
1268 {
1269         /* all verts with (flag & 'flag') rotate */
1270         Nurb *nu;
1271         BPoint *bp;
1272         int a;
1273
1274         for(nu= editnurb->first; nu; nu= nu->next) {
1275                 if(nu->type == CU_NURBS) {
1276                         bp= nu->bp;
1277                         a= nu->pntsu*nu->pntsv;
1278
1279                         while(a--) {
1280                                 if(bp->f1 & flag) {
1281                                         sub_v3_v3(bp->vec, cent);
1282                                         mul_m3_v3(rotmat, bp->vec);
1283                                         add_v3_v3(bp->vec, cent);
1284                                 }
1285                                 bp++;
1286                         }
1287                 }
1288         }
1289 }
1290
1291 static void translateflagNurb(ListBase *editnurb, short flag, float *vec)
1292 {
1293         /* all verts with ('flag' & flag) translate */
1294         Nurb *nu;
1295         BezTriple *bezt;
1296         BPoint *bp;
1297         int a;
1298
1299         for(nu= editnurb->first; nu; nu= nu->next) {
1300                 if(nu->type == CU_BEZIER) {
1301                         a= nu->pntsu;
1302                         bezt= nu->bezt;
1303                         while(a--) {
1304                                 if(bezt->f1 & flag) add_v3_v3(bezt->vec[0], vec);
1305                                 if(bezt->f2 & flag) add_v3_v3(bezt->vec[1], vec);
1306                                 if(bezt->f3 & flag) add_v3_v3(bezt->vec[2], vec);
1307                                 bezt++;
1308                         }
1309                 }
1310                 else {
1311                         a= nu->pntsu*nu->pntsv;
1312                         bp= nu->bp;
1313                         while(a--) {
1314                                 if(bp->f1 & flag) add_v3_v3(bp->vec, vec);
1315                                 bp++;
1316                         }
1317                 }
1318
1319                 test2DNurb(nu);
1320         }
1321 }
1322
1323 static void weightflagNurb(ListBase *editnurb, short flag, float w)
1324 {
1325         Nurb *nu;
1326         BPoint *bp;
1327         int a;
1328
1329         for(nu= editnurb->first; nu; nu= nu->next) {
1330                 if(nu->type == CU_NURBS) {
1331                         a= nu->pntsu*nu->pntsv;
1332                         bp= nu->bp;
1333                         while(a--) {
1334                                 if(bp->f1 & flag) {
1335                                         /* a mode used to exist for replace/multiple but is was unused */
1336                                         bp->vec[3]*= w;
1337                                 }
1338                                 bp++;
1339                         }
1340                 }
1341         }
1342 }
1343
1344 static int deleteflagNurb(bContext *C, wmOperator *UNUSED(op), int flag)
1345 {
1346         Object *obedit= CTX_data_edit_object(C);
1347         Curve *cu= obedit->data;
1348         ListBase *editnurb= curve_get_editcurve(obedit);
1349         Nurb *nu, *next;
1350         BPoint *bp, *bpn, *newbp;
1351         int a, b, newu, newv, sel;
1352
1353         if(obedit && obedit->type==OB_SURF);
1354         else return OPERATOR_CANCELLED;
1355
1356         cu->lastsel= NULL;
1357
1358         nu= editnurb->first;
1359         while(nu) {
1360                 next= nu->next;
1361
1362                 /* is entire nurb selected */
1363                 bp= nu->bp;
1364                 a= nu->pntsu*nu->pntsv;
1365                 while(a) {
1366                         a--;
1367                         if(bp->f1 & flag);
1368                         else break;
1369                         bp++;
1370                 }
1371                 if(a==0) {
1372                         BLI_remlink(editnurb, nu);
1373                         keyIndex_delNurb(cu->editnurb, nu);
1374                         freeNurb(nu); nu=NULL;
1375                 }
1376                 else {
1377                         /* is nurb in U direction selected */
1378                         newv= nu->pntsv;
1379                         bp= nu->bp;
1380                         for(b=0; b<nu->pntsv; b++) {
1381                                 sel= 0;
1382                                 for(a=0; a<nu->pntsu; a++, bp++) {
1383                                         if(bp->f1 & flag) sel++;
1384                                 }
1385                                 if(sel==nu->pntsu) {
1386                                         newv--;
1387                                 }
1388                                 else if(sel>=1) {
1389                                         /* don't delete */
1390                                         break;
1391                                 }
1392                         }
1393                         if(newv!=nu->pntsv && b==nu->pntsv)     {
1394                                 /* delete */
1395                                 bp= nu->bp;
1396                                 bpn = newbp =
1397                                         (BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
1398                                 for(b=0; b<nu->pntsv; b++) {
1399                                         if((bp->f1 & flag)==0) {
1400                                                 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
1401                                                 bpn+= nu->pntsu;
1402                                         } else {
1403                                                 keyIndex_delBP(cu->editnurb, bp);
1404                                         }
1405                                         bp+= nu->pntsu;
1406                                 }
1407                                 nu->pntsv= newv;
1408                                 keyIndex_updateBP(cu->editnurb, nu->bp, newbp, newv * nu->pntsu, 1);
1409                                 MEM_freeN(nu->bp);
1410                                 nu->bp= newbp;
1411                                 clamp_nurb_order_v(nu);
1412
1413                                 nurbs_knot_calc_v(nu);
1414                         }
1415                         else {
1416                                 /* is the nurb in V direction selected */
1417                                 newu= nu->pntsu;
1418                                 for(a=0; a<nu->pntsu; a++) {
1419                                         bp= nu->bp+a;
1420                                         sel= 0;
1421                                         for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
1422                                                 if(bp->f1 & flag) sel++;
1423                                         }
1424                                         if(sel==nu->pntsv) {
1425                                                 newu--;
1426                                         }
1427                                         else if(sel>=1) {
1428                                                 /* don't delete */
1429                                                 break;
1430                                         }
1431                                 }
1432                                 if(newu!=nu->pntsu && a==nu->pntsu)     {
1433                                         /* delete */
1434                                         bp= nu->bp;
1435                                         bpn = newbp =
1436                                                 (BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
1437                                         for(b=0; b<nu->pntsv; b++) {
1438                                                 for(a=0; a<nu->pntsu; a++, bp++) {
1439                                                         if((bp->f1 & flag)==0) {
1440                                                                 *bpn= *bp;
1441                                                                 bpn++;
1442                                                         } else {
1443                                                                 keyIndex_delBP(cu->editnurb, bp);
1444                                                         }
1445                                                 }
1446                                         }
1447                                         keyIndex_updateBP(cu->editnurb, nu->bp, newbp, newu * nu->pntsv, 1);
1448                                         MEM_freeN(nu->bp);
1449                                         nu->bp= newbp;
1450                                         if(newu==1 && nu->pntsv>1) {    /* make a U spline */
1451                                                 nu->pntsu= nu->pntsv;
1452                                                 nu->pntsv= 1;
1453                                                 SWAP(short, nu->orderu, nu->orderv);
1454                                                 clamp_nurb_order_u(nu);
1455                                                 if(nu->knotsv) MEM_freeN(nu->knotsv);
1456                                                 nu->knotsv= NULL;
1457                                         }
1458                                         else {
1459                                                 nu->pntsu= newu;
1460                                                 clamp_nurb_order_u(nu);
1461                                         }
1462                                         nurbs_knot_calc_u(nu);
1463                                 }
1464                         }
1465                 }
1466                 nu= next;
1467         }
1468
1469         return OPERATOR_FINISHED;
1470 }
1471
1472 /* only for OB_SURF */
1473 static short extrudeflagNurb(EditNurb *editnurb, int flag)
1474 {
1475         Nurb *nu;
1476         BPoint *bp, *bpn, *newbp;
1477         int ok= 0, a, u, v, len;
1478
1479         nu= editnurb->nurbs.first;
1480         while(nu) {
1481
1482                 if(nu->pntsv==1) {
1483                         bp= nu->bp;
1484                         a= nu->pntsu;
1485                         while(a) {
1486                                 if(bp->f1 & flag);
1487                                 else break;
1488                                 bp++;
1489                                 a--;
1490                         }
1491                         if(a==0) {
1492                                 ok= 1;
1493                                 newbp =
1494                                         (BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
1495                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
1496                                 bp= newbp+ nu->pntsu;
1497                                 ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu);
1498                                 MEM_freeN(nu->bp);
1499                                 nu->bp= newbp;
1500                                 a= nu->pntsu;
1501                                 while(a--) {
1502                                         select_bpoint(bp, SELECT, flag, HIDDEN);
1503                                         select_bpoint(newbp, DESELECT, flag, HIDDEN);
1504                                         bp++; 
1505                                         newbp++;
1506                                 }
1507
1508                                 nu->pntsv= 2;
1509                                 nu->orderv= 2;
1510                                 nurbs_knot_calc_v(nu);
1511                         }
1512                 }
1513                 else {
1514                         /* which row or column is selected */
1515
1516                         if( isNurbselUV(nu, &u, &v, flag) ) {
1517
1518                                 /* deselect all */
1519                                 bp= nu->bp;
1520                                 a= nu->pntsu*nu->pntsv;
1521                                 while(a--) {
1522                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
1523                                         bp++;
1524                                 }
1525
1526                                 if(u==0 || u== nu->pntsv-1) {       /* row in u-direction selected */
1527                                         ok= 1;
1528                                         newbp =
1529                                                 (BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1)
1530                                                                                   * sizeof(BPoint), "extrudeNurb1");
1531                                         if(u==0) {
1532                                                 len= nu->pntsv*nu->pntsu;
1533                                                 ED_curve_bpcpy(editnurb, newbp+nu->pntsu, nu->bp, len);
1534                                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
1535                                                 bp= newbp;
1536                                         }
1537                                         else {
1538                                                 len= nu->pntsv*nu->pntsu;
1539                                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, len);
1540                                                 ED_curve_bpcpy(editnurb, newbp+len, nu->bp+len-nu->pntsu, nu->pntsu);
1541                                                 bp= newbp+len;
1542                                         }
1543
1544                                         a= nu->pntsu;
1545                                         while(a--) {
1546                                                 select_bpoint(bp, SELECT, flag, HIDDEN);
1547                                                 bp++;
1548                                         }
1549
1550                                         MEM_freeN(nu->bp);
1551                                         nu->bp= newbp;
1552                                         nu->pntsv++;
1553                                         nurbs_knot_calc_v(nu);
1554                                 }
1555                                 else if(v==0 || v== nu->pntsu-1) {          /* collumn in v-direction selected */
1556                                         ok= 1;
1557                                         bpn = newbp =
1558                                                 (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
1559                                         bp= nu->bp;
1560
1561                                         for(a=0; a<nu->pntsv; a++) {
1562                                                 if(v==0) {
1563                                                         *bpn= *bp;
1564                                                         bpn->f1 |= flag;
1565                                                         bpn++;
1566                                                 }
1567                                                 ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu);
1568                                                 bp+= nu->pntsu;
1569                                                 bpn+= nu->pntsu;
1570                                                 if(v== nu->pntsu-1) {
1571                                                         *bpn= *(bp-1);
1572                                                         bpn->f1 |= flag;
1573                                                         bpn++;
1574                                                 }
1575                                         }
1576
1577                                         MEM_freeN(nu->bp);
1578                                         nu->bp= newbp;
1579                                         nu->pntsu++;
1580                                         nurbs_knot_calc_u(nu);
1581                                 }
1582                         }
1583                 }
1584                 nu= nu->next;
1585         }
1586
1587         return ok;
1588 }
1589
1590 static void adduplicateflagNurb(Object *obedit, short flag)
1591 {
1592         ListBase *editnurb= curve_get_editcurve(obedit);
1593         Nurb *nu, *newnu;
1594         BezTriple *bezt, *bezt1;
1595         BPoint *bp, *bp1;
1596         Curve *cu= (Curve*)obedit->data;
1597         int a, b, starta, enda, newu, newv;
1598         char *usel;
1599
1600         cu->lastsel= NULL;
1601
1602         nu= editnurb->last;
1603         while(nu) {
1604                 if(nu->type == CU_BEZIER) {
1605                         bezt= nu->bezt;
1606                         for(a=0; a<nu->pntsu; a++) {
1607                                 enda= -1;
1608                                 starta= a;
1609                                 while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
1610                                         select_beztriple(bezt, DESELECT, flag, HIDDEN);
1611                                         enda=a;
1612                                         if(a>=nu->pntsu-1) break;
1613                                         a++;
1614                                         bezt++;
1615                                 }
1616                                 if(enda>=starta) {
1617                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");  
1618                                         memcpy(newnu, nu, sizeof(Nurb));
1619                                         BLI_addtail(editnurb, newnu);
1620                                         set_actNurb(obedit, newnu);
1621                                         newnu->pntsu= enda-starta+1;
1622                                         newnu->bezt=
1623                                                 (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");  
1624                                         memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
1625
1626                                         b= newnu->pntsu;
1627                                         bezt1= newnu->bezt;
1628                                         while(b--) {
1629                                                 select_beztriple(bezt1, SELECT, flag, HIDDEN);
1630                                                 bezt1++;
1631                                         }
1632
1633                                         if(nu->flagu & CU_NURB_CYCLIC) {
1634                                                 if(starta!=0 || enda!=nu->pntsu-1) {
1635                                                         newnu->flagu &= ~CU_NURB_CYCLIC;
1636                                                 }
1637                                         }
1638                                 }
1639                                 bezt++;
1640                         }
1641                 }
1642                 else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
1643                         bp= nu->bp;
1644                         for(a=0; a<nu->pntsu; a++) {
1645                                 enda= -1;
1646                                 starta= a;
1647                                 while(bp->f1 & flag) {
1648                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
1649                                         enda= a;
1650                                         if(a>=nu->pntsu-1) break;
1651                                         a++;
1652                                         bp++;
1653                                 }
1654                                 if(enda>=starta) {
1655                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");  
1656                                         memcpy(newnu, nu, sizeof(Nurb));
1657                                         set_actNurb(obedit, newnu);
1658                                         BLI_addtail(editnurb, newnu);
1659                                         newnu->pntsu= enda-starta+1;
1660                                         newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
1661                                         memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
1662
1663                                         b= newnu->pntsu;
1664                                         bp1= newnu->bp;
1665                                         while(b--) {
1666                                                 select_bpoint(bp1, SELECT, flag, HIDDEN);
1667                                                 bp1++;
1668                                         }
1669
1670                                         if(nu->flagu & CU_NURB_CYCLIC) {
1671                                                 if(starta!=0 || enda!=nu->pntsu-1) {
1672                                                         newnu->flagu &= ~CU_NURB_CYCLIC;
1673                                                 }
1674                                         }
1675
1676                                         /* knots */
1677                                         newnu->knotsu= NULL;
1678                                         nurbs_knot_calc_u(newnu);
1679                                 }
1680                                 bp++;
1681                         }
1682                 }
1683                 else {
1684                         /* a rectangular area in nurb has to be selected */
1685                         if(isNurbsel(nu)) {
1686                                 usel= MEM_callocN(nu->pntsu, "adduplicateN4");
1687                                 bp= nu->bp;
1688                                 for(a=0; a<nu->pntsv; a++) {
1689                                         for(b=0; b<nu->pntsu; b++, bp++) {
1690                                                 if(bp->f1 & flag) usel[b]++;
1691                                         }
1692                                 }
1693                                 newu= 0;
1694                                 newv= 0;
1695                                 for(a=0; a<nu->pntsu; a++) {
1696                                         if(usel[a]) {
1697                                                 if(newv==0 || usel[a]==newv) {
1698                                                         newv= usel[a];
1699                                                         newu++;
1700                                                 }
1701                                                 else {
1702                                                         newv= 0;
1703                                                         break;
1704                                                 }
1705                                         }
1706                                 }
1707                                 if(newu==0 || newv==0) {
1708                                         if (G.f & G_DEBUG)
1709                                                 printf("Can't duplicate Nurb\n");
1710                                 }
1711                                 else {
1712
1713                                         if(newu==1) SWAP(short, newu, newv);
1714
1715                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
1716                                         memcpy(newnu, nu, sizeof(Nurb));
1717                                         BLI_addtail(editnurb, newnu);
1718                                         set_actNurb(obedit, newnu);
1719                                         newnu->pntsu= newu;
1720                                         newnu->pntsv= newv;
1721                                         newnu->bp =
1722                                                 (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
1723                                         clamp_nurb_order_u(newnu);
1724                                         clamp_nurb_order_v(newnu);
1725                                         
1726                                         newnu->knotsu= newnu->knotsv= NULL;
1727                                         
1728                                         bp= newnu->bp;
1729                                         bp1= nu->bp;
1730                                         for(a=0; a<nu->pntsv; a++) {
1731                                                 for(b=0; b<nu->pntsu; b++, bp1++) {
1732                                                         if(bp1->f1 & flag) {
1733                                                                 memcpy(bp, bp1, sizeof(BPoint));
1734                                                                 select_bpoint(bp1, DESELECT, flag, HIDDEN);
1735                                                                 bp++;
1736                                                         }
1737                                                 }
1738                                         }
1739                                         if (check_valid_nurb_u(newnu)) {
1740                                                 if(nu->pntsu==newnu->pntsu && nu->knotsu) {
1741                                                         newnu->knotsu= MEM_dupallocN( nu->knotsu );
1742                                                 } else {
1743                                                         nurbs_knot_calc_u(newnu);
1744                                                 }
1745                                         }
1746                                         if (check_valid_nurb_v(newnu)) {
1747                                                 if(nu->pntsv==newnu->pntsv && nu->knotsv) {
1748                                                         newnu->knotsv= MEM_dupallocN( nu->knotsv );
1749                                                 } else {
1750                                                         nurbs_knot_calc_v(newnu);
1751                                                 }
1752                                         }
1753                                 }
1754                                 MEM_freeN(usel);
1755                         }
1756                 }
1757
1758                 nu= nu->prev;
1759         }
1760         
1761         /* actnu changed */
1762 }
1763
1764 /**************** switch direction operator ***************/
1765
1766 static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
1767 {
1768         Object *obedit= CTX_data_edit_object(C);
1769         Curve *cu= (Curve*)obedit->data;
1770         EditNurb *editnurb= cu->editnurb;
1771         Nurb *nu;
1772
1773         for(nu= editnurb->nurbs.first; nu; nu= nu->next)
1774                 if(isNurbsel(nu)) {
1775                         switchdirectionNurb(nu);
1776                         keyData_switchDirectionNurb(cu, nu);
1777                 }
1778
1779         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1780         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1781
1782         return OPERATOR_FINISHED;
1783 }
1784
1785 void CURVE_OT_switch_direction(wmOperatorType *ot)
1786 {
1787         /* identifiers */
1788         ot->name= "Switch Direction";
1789         ot->idname= "CURVE_OT_switch_direction";
1790         
1791         /* api callbacks */
1792         ot->exec= switch_direction_exec;
1793         ot->poll= ED_operator_editsurfcurve;
1794
1795         /* flags */
1796         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1797 }
1798
1799 /****************** set weight operator *******************/
1800
1801 static int set_goal_weight_exec(bContext *C, wmOperator *op)
1802 {
1803         Object *obedit= CTX_data_edit_object(C);
1804         ListBase *editnurb= curve_get_editcurve(obedit);
1805         Nurb *nu;
1806         BezTriple *bezt;
1807         BPoint *bp;
1808         float weight= RNA_float_get(op->ptr, "weight");
1809         int a;
1810                                 
1811         for(nu= editnurb->first; nu; nu= nu->next) {
1812                 if(nu->bezt) {
1813                         for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1814                                 if(bezt->f2 & SELECT)
1815                                         bezt->weight= weight;
1816                         }
1817                 }
1818                 else if(nu->bp) {
1819                         for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1820                                 if(bp->f1 & SELECT)
1821                                         bp->weight= weight;
1822                         }
1823                 }
1824         }       
1825
1826         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1827         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1828
1829         return OPERATOR_FINISHED;
1830 }
1831
1832 void CURVE_OT_spline_weight_set(wmOperatorType *ot)
1833 {
1834         /* identifiers */
1835         ot->name= "Set Curve Weight";
1836         ot->idname= "CURVE_OT_spline_weight_set";
1837         
1838         /* api callbacks */
1839         ot->exec= set_goal_weight_exec;
1840         ot->invoke= WM_operator_props_popup;
1841         ot->poll= ED_operator_editsurfcurve;
1842
1843         /* flags */
1844         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1845
1846         /* properties */
1847         RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
1848 }
1849
1850 /******************* set radius operator ******************/
1851
1852 static int set_radius_exec(bContext *C, wmOperator *op)
1853 {
1854         Object *obedit= CTX_data_edit_object(C);
1855         ListBase *editnurb= curve_get_editcurve(obedit);
1856         Nurb *nu;
1857         BezTriple *bezt;
1858         BPoint *bp;
1859         float radius= RNA_float_get(op->ptr, "radius");
1860         int a;
1861         
1862         for(nu= editnurb->first; nu; nu= nu->next) {
1863                 if(nu->bezt) {
1864                         for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1865                                 if(bezt->f2 & SELECT)
1866                                         bezt->radius= radius;
1867                         }
1868                 }
1869                 else if(nu->bp) {
1870                         for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1871                                 if(bp->f1 & SELECT)
1872                                         bp->radius= radius;
1873                         }
1874                 }
1875         }       
1876
1877         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1878         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1879
1880         return OPERATOR_FINISHED;
1881 }
1882
1883 void CURVE_OT_radius_set(wmOperatorType *ot)
1884 {
1885         /* identifiers */
1886         ot->name= "Set Curve Radius";
1887         ot->idname= "CURVE_OT_radius_set";
1888         
1889         /* api callbacks */
1890         ot->exec= set_radius_exec;
1891         ot->invoke= WM_operator_props_popup;
1892         ot->poll= ED_operator_editsurfcurve;
1893
1894         /* flags */
1895         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1896
1897         /* properties */
1898         RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "", 0.0001f, 10.0f);
1899 }
1900
1901 /********************* smooth operator ********************/
1902
1903 static int smooth_exec(bContext *C, wmOperator *UNUSED(op))
1904 {
1905         Object *obedit= CTX_data_edit_object(C);
1906         ListBase *editnurb= curve_get_editcurve(obedit);
1907         Nurb *nu;
1908         BezTriple *bezt, *beztOrig;
1909         BPoint *bp, *bpOrig;
1910         float val, newval, offset;
1911         int a, i, change = 0;
1912         
1913         for(nu= editnurb->first; nu; nu= nu->next) {
1914                 if(nu->bezt) {
1915                         change = 0;
1916                         beztOrig = MEM_dupallocN( nu->bezt );
1917                         for(bezt=nu->bezt+1, a=1; a<nu->pntsu-1; a++, bezt++) {
1918                                 if(bezt->f2 & SELECT) {
1919                                         for(i=0; i<3; i++) {
1920                                                 val = bezt->vec[1][i];
1921                                                 newval = ((beztOrig+(a-1))->vec[1][i] * 0.5) + ((beztOrig+(a+1))->vec[1][i] * 0.5);
1922                                                 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1923                                                 /* offset handles */
1924                                                 bezt->vec[1][i] += offset;
1925                                                 bezt->vec[0][i] += offset;
1926                                                 bezt->vec[2][i] += offset;
1927                                         }
1928                                         change = 1;
1929                                 }
1930                         }
1931                         MEM_freeN(beztOrig);
1932                         if (change)
1933                                 calchandlesNurb(nu);
1934                 } else if (nu->bp) {
1935                         bpOrig = MEM_dupallocN( nu->bp );
1936                         /* Same as above, keep these the same! */
1937                         for(bp=nu->bp+1, a=1; a<nu->pntsu-1; a++, bp++) {
1938                                 if(bp->f1 & SELECT) {
1939                                         for(i=0; i<3; i++) {
1940                                                 val = bp->vec[i];
1941                                                 newval = ((bpOrig+(a-1))->vec[i] * 0.5) + ((bpOrig+(a+1))->vec[i] * 0.5);
1942                                                 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1943                                         
1944                                                 bp->vec[i] += offset;
1945                                         }
1946                                 }
1947                         }
1948                         MEM_freeN(bpOrig);
1949                 }
1950         }
1951
1952         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1953         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1954
1955         return OPERATOR_FINISHED;
1956 }
1957
1958 void CURVE_OT_smooth(wmOperatorType *ot)
1959 {
1960         /* identifiers */
1961         ot->name= "Smooth";
1962         ot->idname= "CURVE_OT_smooth";
1963         
1964         /* api callbacks */
1965         ot->exec= smooth_exec;
1966         ot->poll= ED_operator_editsurfcurve;
1967
1968         /* flags */
1969         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1970 }
1971
1972 /**************** smooth curve radius operator *************/
1973
1974 /* TODO, make smoothing distance based */
1975 static int smooth_radius_exec(bContext *C, wmOperator *UNUSED(op))
1976 {
1977         Object *obedit= CTX_data_edit_object(C);
1978         ListBase *editnurb= curve_get_editcurve(obedit);
1979         Nurb *nu;
1980         BezTriple *bezt;
1981         BPoint *bp;
1982         int a;
1983         
1984         /* use for smoothing */
1985         int last_sel;
1986         int start_sel, end_sel; /* selection indicies, inclusive */
1987         float start_rad, end_rad, fac, range;
1988         
1989         for(nu= editnurb->first; nu; nu= nu->next) {
1990                 if(nu->bezt) {
1991                         
1992                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1993                                 /* loop over selection segments of a curve, smooth each */
1994                                 
1995                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1996                                 start_sel = end_sel = -1;
1997                                 for(bezt=nu->bezt+last_sel, a=last_sel; a<nu->pntsu; a++, bezt++) {
1998                                         if(bezt->f2 & SELECT) {
1999                                                 start_sel = a;
2000                                                 break;
2001                                         }
2002                                 }
2003                                 /* incase there are no other selected verts */
2004                                 end_sel = start_sel;
2005                                 for(bezt=nu->bezt+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bezt++) {
2006                                         if((bezt->f2 & SELECT)==0) {
2007                                                 break;
2008                                         }
2009                                         end_sel = a;
2010                                 }
2011                                 
2012                                 if (start_sel == -1) {
2013                                         last_sel = nu->pntsu; /* next... */
2014                                 } else {
2015                                         last_sel = end_sel; /* before we modify it */
2016                                         
2017                                         /* now blend between start and end sel */
2018                                         start_rad = end_rad = -1.0;
2019                                         
2020                                         if (start_sel == end_sel) {
2021                                                 /* simple, only 1 point selected */
2022                                                 if (start_sel>0)                                                start_rad = (nu->bezt+start_sel-1)->radius;
2023                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bezt+start_sel+1)->radius;
2024                                                 
2025                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bezt+start_sel)->radius = (start_rad + end_rad)/2;
2026                                                 else if (start_rad >= 0.0)                              (nu->bezt+start_sel)->radius = start_rad;
2027                                                 else if (end_rad >= 0.0)                                (nu->bezt+start_sel)->radius = end_rad;
2028                                         } else {
2029                                                 /* if endpoints selected, then use them */
2030                                                 if (start_sel==0) {
2031                                                         start_rad = (nu->bezt+start_sel)->radius;
2032                                                         start_sel++; /* we dont want to edit the selected endpoint */
2033                                                 } else {
2034                                                         start_rad = (nu->bezt+start_sel-1)->radius;
2035                                                 }
2036                                                 if (end_sel==nu->pntsu-1) {
2037                                                         end_rad = (nu->bezt+end_sel)->radius;
2038                                                         end_sel--; /* we dont want to edit the selected endpoint */
2039                                                 } else {
2040                                                         end_rad = (nu->bezt+end_sel+1)->radius;
2041                                                 }
2042                                                 
2043                                                 /* Now Blend between the points */
2044                                                 range = (float)(end_sel - start_sel) + 2.0f;
2045                                                 for(bezt=nu->bezt+start_sel, a=start_sel; a<=end_sel; a++, bezt++) {
2046                                                         fac = (float)(1+a-start_sel) / range;
2047                                                         bezt->radius = start_rad*(1.0-fac) + end_rad*fac;
2048                                                 }
2049                                         }
2050                                 }
2051                         }
2052                 } else if (nu->bp) {
2053                         /* Same as above, keep these the same! */
2054                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
2055                                 /* loop over selection segments of a curve, smooth each */
2056                                 
2057                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
2058                                 start_sel = end_sel = -1;
2059                                 for(bp=nu->bp+last_sel, a=last_sel; a<nu->pntsu; a++, bp++) {
2060                                         if(bp->f1 & SELECT) {
2061                                                 start_sel = a;
2062                                                 break;
2063                                         }
2064                                 }
2065                                 /* incase there are no other selected verts */
2066                                 end_sel = start_sel;
2067                                 for(bp=nu->bp+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bp++) {
2068                                         if((bp->f1 & SELECT)==0) {
2069                                                 break;
2070                                         }
2071                                         end_sel = a;
2072                                 }
2073                                 
2074                                 if (start_sel == -1) {
2075                                         last_sel = nu->pntsu; /* next... */
2076                                 } else {
2077                                         last_sel = end_sel; /* before we modify it */
2078                                         
2079                                         /* now blend between start and end sel */
2080                                         start_rad = end_rad = -1.0;
2081                                         
2082                                         if (start_sel == end_sel) {
2083                                                 /* simple, only 1 point selected */
2084                                                 if (start_sel>0)                                                start_rad = (nu->bp+start_sel-1)->radius;
2085                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bp+start_sel+1)->radius;
2086                                                 
2087                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bp+start_sel)->radius = (start_rad + end_rad)/2;
2088                                                 else if (start_rad >= 0.0)                              (nu->bp+start_sel)->radius = start_rad;
2089                                                 else if (end_rad >= 0.0)                                (nu->bp+start_sel)->radius = end_rad;
2090                                         } else {
2091                                                 /* if endpoints selected, then use them */
2092                                                 if (start_sel==0) {
2093                                                         start_rad = (nu->bp+start_sel)->radius;
2094                                                         start_sel++; /* we dont want to edit the selected endpoint */
2095                                                 } else {
2096                                                         start_rad = (nu->bp+start_sel-1)->radius;
2097                                                 }
2098                                                 if (end_sel==nu->pntsu-1) {
2099                                                         end_rad = (nu->bp+end_sel)->radius;
2100                                                         end_sel--; /* we dont want to edit the selected endpoint */
2101                                                 } else {
2102                                                         end_rad = (nu->bp+end_sel+1)->radius;
2103                                                 }
2104                                                 
2105                                                 /* Now Blend between the points */
2106                                                 range = (float)(end_sel - start_sel) + 2.0f;
2107                                                 for(bp=nu->bp+start_sel, a=start_sel; a<=end_sel; a++, bp++) {
2108                                                         fac = (float)(1+a-start_sel) / range;
2109                                                         bp->radius = start_rad*(1.0-fac) + end_rad*fac;
2110                                                 }
2111                                         }
2112                                 }
2113                         }
2114                 }
2115         }
2116
2117         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2118         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2119
2120         return OPERATOR_FINISHED;
2121 }
2122
2123 void CURVE_OT_smooth_radius(wmOperatorType *ot)
2124 {
2125         /* identifiers */
2126         ot->name= "Smooth Curve Radius";
2127         ot->idname= "CURVE_OT_smooth_radius";
2128         
2129         /* api clastbacks */
2130         ot->exec= smooth_radius_exec;
2131         ot->poll= ED_operator_editsurfcurve;
2132         
2133         /* flags */
2134         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2135 }
2136
2137 /***************** selection utility *************************/
2138
2139 /* next == 1 -> select next             */
2140 /* next == -1 -> select previous        */
2141 /* cont == 1 -> select continuously     */
2142 /* selstatus, inverts behaviour         */
2143 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus)
2144 {
2145         Nurb *nu;
2146         BezTriple *bezt;
2147         BPoint *bp;
2148         int a;
2149         short lastsel= 0, sel=0;
2150         
2151         if(next==0) return;
2152         
2153         for(nu= editnurb->first; nu; nu= nu->next) {
2154                 lastsel=0;
2155                 if(nu->type == CU_BEZIER) {                     
2156                         a= nu->pntsu;
2157                         bezt= nu->bezt;
2158                         if(next < 0) bezt= (nu->bezt + (a-1));
2159                         while(a--) {
2160                                 if(a-abs(next) < 0) break;
2161                                 sel= 0;
2162                                 if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & SELECT) || (selstatus==0))) {
2163                                         bezt+=next;
2164                                         if(!(bezt->f2 & SELECT) || (selstatus==0)) {
2165                                                 sel= select_beztriple(bezt, selstatus, 1, VISIBLE);     
2166                                                 if((sel==1) && (cont==0)) lastsel= 1;
2167                                         }                                                       
2168                                 }
2169                                 else {
2170                                         bezt+=next;
2171                                         lastsel= 0;
2172                                 }
2173                                 /* move around in zigzag way so that we go through each */                              
2174                                 bezt-=(next-next/abs(next));                            
2175                         }
2176                 }
2177                 else {
2178                         a= nu->pntsu*nu->pntsv;
2179                         bp= nu->bp;
2180                         if(next < 0) bp= (nu->bp + (a-1));
2181                         while(a--) {
2182                                 if(a-abs(next) < 0) break;
2183                                 sel=0;
2184                                 if((lastsel==0) && (bp->hide==0) && ((bp->f1 & SELECT) || (selstatus==0))) {
2185                                         bp+=next;
2186                                         if(!(bp->f1 & SELECT) || (selstatus==0)) {
2187                                                 sel= select_bpoint(bp, selstatus, 1, VISIBLE);
2188                                                 if((sel==1) && (cont==0)) lastsel= 1;
2189                                         }                       
2190                                 }
2191                                 else {
2192                                         bp+=next;
2193                                         lastsel= 0;
2194                                 }
2195                                 /* move around in zigzag way so that we go through each */
2196                                 bp-=(next-next/abs(next));                              
2197                         }
2198                 }
2199         }
2200 }
2201
2202 /**************** select start/end operators **************/
2203
2204 /* (de)selects first or last of visible part of each Nurb depending on selFirst     */
2205 /* selFirst: defines the end of which to select                                     */
2206 /* doswap: defines if selection state of each first/last control point is swapped   */
2207 /* selstatus: selection status in case doswap is false                              */
2208 void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus)
2209 {
2210         ListBase *editnurb= curve_get_editcurve(obedit);
2211         Nurb *nu;
2212         BPoint *bp;
2213         BezTriple *bezt;
2214         Curve *cu;
2215         int a;
2216         short sel;
2217
2218         if(obedit==0) return;
2219
2220         cu= (Curve*)obedit->data;
2221         cu->lastsel= NULL;
2222
2223         for(nu= editnurb->first; nu; nu= nu->next) {
2224                 sel= 0;
2225                 if(nu->type == CU_BEZIER) {
2226                         a= nu->pntsu;
2227                         
2228                         /* which point? */
2229                         if(selfirst==0) { /* select last */ 
2230                                 bezt= (nu->bezt + (a-1));
2231                         }
2232                         else { /* select first */
2233                                 bezt= nu->bezt;
2234                         }
2235                         
2236                         while(a--) {
2237                                 if(doswap) sel= swap_selection_beztriple(bezt);
2238                                 else sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
2239                                 
2240                                 if(sel==1) break;
2241                         }
2242                 }
2243                 else {
2244                         a= nu->pntsu*nu->pntsv;
2245                         
2246                         /* which point? */
2247                         if(selfirst==0) { /* select last */
2248                                 bp= (nu->bp + (a-1));
2249                         }
2250                         else{ /* select first */
2251                                 bp= nu->bp;
2252                         }
2253
2254                         while(a--) {
2255                                 if (bp->hide == 0) {
2256                                         if(doswap) sel= swap_selection_bpoint(bp);
2257                                         else sel= select_bpoint(bp, selstatus, 1, VISIBLE);
2258                                         
2259                                         if(sel==1) break;
2260                                 }
2261                         }
2262                 }
2263         }
2264 }
2265
2266 static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
2267 {
2268         Object *obedit= CTX_data_edit_object(C);
2269
2270         selectend_nurb(obedit, FIRST, 1, DESELECT);
2271         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2272
2273         return OPERATOR_FINISHED;
2274 }
2275
2276 void CURVE_OT_de_select_first(wmOperatorType *ot)
2277 {
2278         /* identifiers */
2279         ot->name= "Select or Deselect First";
2280         ot->idname= "CURVE_OT_de_select_first";
2281         
2282         /* api cfirstbacks */
2283         ot->exec= de_select_first_exec;
2284         ot->poll= ED_operator_editcurve;
2285         
2286         /* flags */
2287         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2288 }
2289
2290 static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
2291 {
2292         Object *obedit= CTX_data_edit_object(C);
2293
2294         selectend_nurb(obedit, LAST, 1, DESELECT);
2295         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2296
2297         return OPERATOR_FINISHED;
2298 }
2299
2300 void CURVE_OT_de_select_last(wmOperatorType *ot)
2301 {
2302         /* identifiers */
2303         ot->name= "Select or Deselect Last";
2304         ot->idname= "CURVE_OT_de_select_last";
2305         
2306         /* api clastbacks */
2307         ot->exec= de_select_last_exec;
2308         ot->poll= ED_operator_editcurve;
2309         
2310         /* flags */
2311         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2312 }
2313
2314 /******************* de select all operator ***************/
2315
2316 static short nurb_has_selected_cps(ListBase *editnurb)
2317 {
2318         Nurb *nu;
2319         BezTriple *bezt;
2320         BPoint *bp;
2321         int a;
2322
2323         for(nu= editnurb->first; nu; nu= nu->next) {
2324                 if(nu->type == CU_BEZIER) {
2325                         a= nu->pntsu;
2326                         bezt= nu->bezt;
2327                         while(a--) {
2328                                 if(bezt->hide==0) {
2329                                         if((bezt->f1 & SELECT)
2330                                         || (bezt->f2 & SELECT)
2331                                         || (bezt->f3 & SELECT)) return 1;
2332                                 }
2333                                 bezt++;
2334                         }
2335                 }
2336                 else {
2337                         a= nu->pntsu*nu->pntsv;
2338                         bp= nu->bp;
2339                         while(a--) {
2340                                 if((bp->hide==0) && (bp->f1 & SELECT)) return 1;
2341                                 bp++;
2342                         }
2343                 }
2344         }
2345         
2346         return 0;
2347 }
2348
2349 static int de_select_all_exec(bContext *C, wmOperator *op)
2350 {
2351         Object *obedit= CTX_data_edit_object(C);
2352         ListBase *editnurb= curve_get_editcurve(obedit);
2353         int action = RNA_enum_get(op->ptr, "action");
2354
2355         if (action == SEL_TOGGLE) {
2356                 action = SEL_SELECT;
2357                 if(nurb_has_selected_cps(editnurb))
2358                         action = SEL_DESELECT;
2359         }
2360
2361         switch (action) {
2362                 case SEL_SELECT:
2363                         CU_select_all(obedit);
2364                         break;
2365                 case SEL_DESELECT:
2366                         CU_deselect_all(obedit);
2367                         break;
2368                 case SEL_INVERT:
2369                         CU_select_swap(obedit);
2370                         break;
2371         }
2372         
2373         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2374
2375         return OPERATOR_FINISHED;
2376 }
2377
2378 void CURVE_OT_select_all(wmOperatorType *ot)
2379 {
2380         /* identifiers */
2381         ot->name= "Select or Deselect All";
2382         ot->idname= "CURVE_OT_select_all";
2383         
2384         /* api callbacks */
2385         ot->exec= de_select_all_exec;
2386         ot->poll= ED_operator_editsurfcurve;
2387         
2388         /* flags */
2389         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2390
2391         /* properties */
2392         WM_operator_properties_select_all(ot);
2393 }
2394
2395 /********************** hide operator *********************/
2396
2397 static int hide_exec(bContext *C, wmOperator *op)
2398 {
2399         Object *obedit= CTX_data_edit_object(C);
2400         Curve *cu= obedit->data;
2401         ListBase *editnurb= curve_get_editcurve(obedit);
2402         Nurb *nu;
2403         BPoint *bp;
2404         BezTriple *bezt;
2405         int a, sel, invert= RNA_boolean_get(op->ptr, "unselected");
2406
2407         for(nu= editnurb->first; nu; nu= nu->next) {
2408                 if(nu->type == CU_BEZIER) {
2409                         bezt= nu->bezt;
2410                         a= nu->pntsu;
2411                         sel= 0;
2412                         while(a--) {
2413                                 if(invert == 0 && BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
2414                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
2415                                         bezt->hide= 1;
2416                                 }
2417                                 else if(invert && !BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
2418                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
2419                                         bezt->hide= 1;
2420                                 }
2421                                 if(bezt->hide) sel++;
2422                                 bezt++;
2423                         }
2424                         if(sel==nu->pntsu) nu->hide= 1;
2425                 }
2426                 else {
2427                         bp= nu->bp;
2428                         a= nu->pntsu*nu->pntsv;
2429                         sel= 0;
2430                         while(a--) {
2431                                 if(invert==0 && (bp->f1 & SELECT)) {
2432                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
2433                                         bp->hide= 1;
2434                                 }
2435                                 else if(invert && (bp->f1 & SELECT)==0) {
2436                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
2437                                         bp->hide= 1;
2438                                 }
2439                                 if(bp->hide) sel++;
2440                                 bp++;
2441                         }
2442                         if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
2443                 }
2444         }
2445
2446         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2447         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2448
2449         return OPERATOR_FINISHED;       
2450 }
2451
2452 void CURVE_OT_hide(wmOperatorType *ot)
2453 {
2454         /* identifiers */
2455         ot->name= "Hide Selected";
2456         ot->idname= "CURVE_OT_hide";
2457         
2458         /* api callbacks */
2459         ot->exec= hide_exec;
2460         ot->poll= ED_operator_editsurfcurve;
2461         
2462         /* flags */
2463         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2464         
2465         /* props */
2466         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
2467 }
2468
2469 /********************** reveal operator *********************/
2470
2471 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
2472 {
2473         Object *obedit= CTX_data_edit_object(C);
2474         ListBase *editnurb= curve_get_editcurve(obedit);
2475         Nurb *nu;
2476         BPoint *bp;
2477         BezTriple *bezt;
2478         int a;
2479
2480         for(nu= editnurb->first; nu; nu= nu->next) {
2481                 nu->hide= 0;
2482                 if(nu->type == CU_BEZIER) {
2483                         bezt= nu->bezt;
2484                         a= nu->pntsu;
2485                         while(a--) {
2486                                 if(bezt->hide) {
2487                                         select_beztriple(bezt, SELECT, 1, HIDDEN);
2488                                         bezt->hide= 0;
2489                                 }
2490                                 bezt++;
2491                         }
2492                 }
2493                 else {
2494                         bp= nu->bp;
2495                         a= nu->pntsu*nu->pntsv;
2496                         while(a--) {
2497                                 if(bp->hide) {
2498                                         select_bpoint(bp, SELECT, 1, HIDDEN);
2499                                         bp->hide= 0;
2500                                 }
2501                                 bp++;
2502                         }
2503                 }
2504         }
2505
2506         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2507         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2508
2509         return OPERATOR_FINISHED;       
2510 }
2511
2512 void CURVE_OT_reveal(wmOperatorType *ot)
2513 {
2514         /* identifiers */
2515         ot->name= "Reveal Hidden";
2516         ot->idname= "CURVE_OT_reveal";
2517         
2518         /* api callbacks */
2519         ot->exec= reveal_exec;
2520         ot->poll= ED_operator_editsurfcurve;
2521         
2522         /* flags */
2523         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2524 }
2525
2526 /********************** select invert operator *********************/
2527
2528 static int select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
2529 {
2530         Object *obedit= CTX_data_edit_object(C);
2531         Curve *cu= obedit->data;
2532         ListBase *editnurb= curve_get_editcurve(obedit);
2533         Nurb *nu;
2534         BPoint *bp;
2535         BezTriple *bezt;
2536         int a;
2537
2538         cu->lastsel= NULL;
2539
2540         for(nu= editnurb->first; nu; nu= nu->next) {
2541                 if(nu->type == CU_BEZIER) {
2542                         bezt= nu->bezt;
2543                         a= nu->pntsu;
2544                         while(a--) {
2545                                 if(bezt->hide==0) {
2546                                         bezt->f2 ^= SELECT; /* always do the center point */
2547                                         if((cu->drawflag & CU_HIDE_HANDLES)==0) {
2548                                                 bezt->f1 ^= SELECT;
2549                                                 bezt->f3 ^= SELECT;
2550                                         }
2551                                 }
2552                                 bezt++;
2553                         }
2554                 }
2555                 else {
2556                         bp= nu->bp;
2557                         a= nu->pntsu*nu->pntsv;
2558                         while(a--) {
2559                                 swap_selection_bpoint(bp);
2560                                 bp++;
2561                         }
2562                 }
2563         }
2564
2565         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2566
2567         return OPERATOR_FINISHED;       
2568 }
2569
2570 void CURVE_OT_select_inverse(wmOperatorType *ot)
2571 {
2572         /* identifiers */
2573         ot->name= "Select Inverse";
2574         ot->idname= "CURVE_OT_select_inverse";
2575         
2576         /* api callbacks */
2577         ot->exec= select_inverse_exec;
2578         ot->poll= ED_operator_editsurfcurve;
2579         
2580         /* flags */
2581         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2582 }
2583
2584 /********************** subdivide operator *********************/
2585
2586 /** Divide the line segments associated with the currently selected
2587  * curve nodes (Bezier or NURB). If there are no valid segment
2588  * selections within the current selection, nothing happens.
2589  *
2590  * @deffunc subdividenurb subdivideNurb(void)
2591  * @return Nothing
2592  * @param  None
2593 */
2594
2595 static void subdividenurb(Object *obedit, int number_cuts)
2596 {
2597         Curve *cu= obedit->data;
2598         EditNurb *editnurb= cu->editnurb;
2599         Nurb *nu;
2600         BezTriple *prevbezt, *bezt, *beztnew, *beztn;
2601         BPoint *bp, *prevbp, *bpnew, *bpn;
2602         float vec[15];
2603         int a, b, sel, amount, *usel, *vsel, i;
2604         float factor;
2605
2606    // printf("*** subdivideNurb: entering subdivide\n");
2607
2608         for(nu= editnurb->nurbs.first; nu; nu= nu->next) {
2609                 amount= 0;
2610                 if(nu->type == CU_BEZIER) {
2611                 /* 
2612                    Insert a point into a 2D Bezier curve. 
2613                    Endpoints are preserved. Otherwise, all selected and inserted points are 
2614                    newly created. Old points are discarded.
2615                 */
2616                         /* count */
2617                         if(nu->flagu & CU_NURB_CYCLIC) {
2618                                 a= nu->pntsu;
2619                                 bezt= nu->bezt;
2620                                 prevbezt= bezt+(a-1);
2621                         }
2622                         else {
2623                                 a= nu->pntsu-1;
2624                                 prevbezt= nu->bezt;
2625                                 bezt= prevbezt+1;
2626                         }
2627                         while(a--) {
2628                                 if( BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) amount+=number_cuts;
2629                                 prevbezt= bezt;
2630                                 bezt++;
2631                         }
2632
2633                         if(amount) {
2634                                 /* insert */
2635                                 beztnew =
2636                                         (BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
2637                                 beztn= beztnew;
2638                                 if(nu->flagu & CU_NURB_CYCLIC) {
2639                                         a= nu->pntsu;
2640                                         bezt= nu->bezt;
2641                                         prevbezt= bezt+(a-1);
2642                                 }
2643                                 else {
2644                                         a= nu->pntsu-1;
2645                                         prevbezt= nu->bezt;
2646                                         bezt= prevbezt+1;
2647                                 }
2648                                 while(a--) {
2649                                         memcpy(beztn, prevbezt, sizeof(BezTriple));
2650                                         keyIndex_updateBezt(editnurb, prevbezt, beztn, 1, 0);
2651                                         beztn++;
2652
2653                                         if( BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
2654                                                 float prevvec[3][3];
2655
2656                                                 memcpy(prevvec, prevbezt->vec, sizeof(float) * 9);
2657
2658                                                 for (i = 0; i < number_cuts; i++) {
2659                                                         factor = 1.0f / (number_cuts + 1 - i);
2660
2661                                                         memcpy(beztn, bezt, sizeof(BezTriple));
2662
2663                                                         /* midpoint subdividing */
2664                                                         interp_v3_v3v3(vec, prevvec[1], prevvec[2], factor);
2665                                                         interp_v3_v3v3(vec+3, prevvec[2], bezt->vec[0], factor);
2666                                                         interp_v3_v3v3(vec+6, bezt->vec[0], bezt->vec[1], factor);
2667
2668                                                         interp_v3_v3v3(vec+9, vec, vec+3, factor);
2669                                                         interp_v3_v3v3(vec+12, vec+3, vec+6, factor);
2670
2671                                                         /* change handle of prev beztn */
2672                                                         VECCOPY((beztn-1)->vec[2], vec);
2673                                                         /* new point */
2674                                                         VECCOPY(beztn->vec[0], vec+9);
2675                                                         interp_v3_v3v3(beztn->vec[1], vec+9, vec+12, factor);
2676                                                         VECCOPY(beztn->vec[2], vec+12);
2677                                                         /* handle of next bezt */
2678                                                         if(a==0 && i == number_cuts - 1 && (nu->flagu & CU_NURB_CYCLIC)) {VECCOPY(beztnew->vec[0], vec+6);}
2679                                                         else {VECCOPY(bezt->vec[0], vec+6);}
2680
2681                                                         beztn->radius = (prevbezt->radius + bezt->radius)/2;
2682                                                         beztn->weight = (prevbezt->weight + bezt->weight)/2;
2683
2684                                                         memcpy(prevvec, beztn->vec, sizeof(float) * 9);
2685                                                         beztn++;
2686                                                 }
2687                                         }
2688
2689                                         prevbezt= bezt;
2690                                         bezt++;
2691                                 }
2692                                 /* last point */
2693                                 if((nu->flagu & CU_NURB_CYCLIC)==0) {
2694                                         memcpy(beztn, prevbezt, sizeof(BezTriple));
2695                                         keyIndex_updateBezt(editnurb, prevbezt, beztn, 1, 0);
2696                                 }
2697
2698                                 MEM_freeN(nu->bezt);
2699                                 nu->bezt= beztnew;
2700                                 nu->pntsu+= amount;
2701
2702                                 calchandlesNurb(nu);
2703                         }
2704                 } /* End of 'if(nu->type == CU_BEZIER)' */
2705                 else if (nu->pntsv==1) {
2706                 /* 
2707                    All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves 
2708                    are handled together with the regular NURB plane division, as it 
2709                    should be. I split it off just now, let's see if it is
2710                    stable... nzc 30-5-'00
2711                  */
2712                         /* count */
2713                         if(nu->flagu & CU_NURB_CYCLIC) {
2714                                 a= nu->pntsu;
2715                                 bp= nu->bp;
2716                                 prevbp= bp+(a-1);
2717                         }
2718                         else {
2719                                 a= nu->pntsu-1;
2720                                 prevbp= nu->bp;
2721                                 bp= prevbp+1;
2722                         }
2723                         while(a--) {
2724                                 if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount+=number_cuts;
2725                                 prevbp= bp;
2726                                 bp++;
2727                         }
2728
2729                         if(amount) {
2730                                 /* insert */
2731                                 bpnew =
2732                                         (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
2733                                 bpn= bpnew;
2734
2735                                 if(nu->flagu & CU_NURB_CYCLIC) {
2736                                         a= nu->pntsu;
2737                                         bp= nu->bp;
2738                                         prevbp= bp+(a-1);
2739                                 }
2740                                 else {
2741                                         a= nu->pntsu-1;
2742                                         prevbp= nu->bp;
2743                                         bp= prevbp+1;
2744                                 }
2745                                 while(a--) {
2746                                         memcpy(bpn, prevbp, sizeof(BPoint));
2747                                         keyIndex_updateBP(editnurb, prevbp, bpn, 1, 0);
2748                                         bpn++;
2749
2750                                         if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) {
2751                                  // printf("*** subdivideNurb: insert 'linear' point\n");
2752                                                 for (i = 0; i < number_cuts; i++) {
2753                                                         factor = (float)(i + 1) / (number_cuts + 1);
2754
2755                                                         memcpy(bpn, bp, sizeof(BPoint));
2756                                                         interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
2757                                                         bpn++;
2758                                                 }
2759
2760                                         }
2761                                         prevbp= bp;
2762                                         bp++;
2763                                 }
2764                                 if((nu->flagu & CU_NURB_CYCLIC)==0) { /* last point */
2765                                         memcpy(bpn, prevbp, sizeof(BPoint));
2766                                         keyIndex_updateBP(editnurb, prevbp, bpn, 1, 0);
2767                                 }
2768
2769                                 MEM_freeN(nu->bp);
2770                                 nu->bp= bpnew;
2771                                 nu->pntsu+= amount;
2772
2773                                 if(nu->type & CU_NURBS) {
2774                                         nurbs_knot_calc_u(nu);
2775                                 }
2776                         }
2777                 } /* End of 'else if(nu->pntsv==1)' */
2778                 else if(nu->type == CU_NURBS) {
2779                 /* This is a very strange test ... */
2780                 /** 
2781                    Subdivide NURB surfaces - nzc 30-5-'00 -
2782            
2783                          Subdivision of a NURB curve can be effected by adding a 
2784                    control point (insertion of a knot), or by raising the
2785                    degree of the functions used to build the NURB. The
2786                    e