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