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