merge with trunk at r31523
[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, *fp, *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;
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;
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                         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                                         bp->vec[0]-=cent[0];
1284                                         bp->vec[1]-=cent[1];
1285                                         bp->vec[2]-=cent[2];
1286                                         mul_m3_v3(rotmat, bp->vec);
1287                                         bp->vec[0]+=cent[0];
1288                                         bp->vec[1]+=cent[1];
1289                                         bp->vec[2]+=cent[2];
1290                                 }
1291                                 bp++;
1292                         }
1293                 }
1294         }
1295 }
1296
1297 static void translateflagNurb(ListBase *editnurb, short flag, float *vec)
1298 {
1299         /* all verts with ('flag' & flag) translate */
1300         Nurb *nu;
1301         BezTriple *bezt;
1302         BPoint *bp;
1303         int a;
1304
1305         for(nu= editnurb->first; nu; nu= nu->next) {
1306                 if(nu->type == CU_BEZIER) {
1307                         a= nu->pntsu;
1308                         bezt= nu->bezt;
1309                         while(a--) {
1310                                 if(bezt->f1 & flag) add_v3_v3(bezt->vec[0], vec);
1311                                 if(bezt->f2 & flag) add_v3_v3(bezt->vec[1], vec);
1312                                 if(bezt->f3 & flag) add_v3_v3(bezt->vec[2], vec);
1313                                 bezt++;
1314                         }
1315                 }
1316                 else {
1317                         a= nu->pntsu*nu->pntsv;
1318                         bp= nu->bp;
1319                         while(a--) {
1320                                 if(bp->f1 & flag) add_v3_v3(bp->vec, vec);
1321                                 bp++;
1322                         }
1323                 }
1324
1325                 test2DNurb(nu);
1326         }
1327 }
1328
1329 static void weightflagNurb(ListBase *editnurb, short flag, float w, int mode)   /* mode==0: replace, mode==1: multiply */
1330 {
1331         Nurb *nu;
1332         BPoint *bp;
1333         int a;
1334
1335         for(nu= editnurb->first; nu; nu= nu->next) {
1336                 if(nu->type == CU_NURBS) {
1337                         a= nu->pntsu*nu->pntsv;
1338                         bp= nu->bp;
1339                         while(a--) {
1340                                 if(bp->f1 & flag) {
1341                                         if(mode==1) bp->vec[3]*= w;
1342                                         else bp->vec[3]= w;
1343                                 }
1344                                 bp++;
1345                         }
1346                 }
1347         }
1348 }
1349
1350 static int deleteflagNurb(bContext *C, wmOperator *op, int flag)
1351 {
1352         Object *obedit= CTX_data_edit_object(C);
1353         Curve *cu= obedit->data;
1354         ListBase *editnurb= curve_get_editcurve(obedit);
1355         Nurb *nu, *next;
1356         BPoint *bp, *bpn, *newbp;
1357         int a, b, newu, newv, sel;
1358
1359         if(obedit && obedit->type==OB_SURF);
1360         else return OPERATOR_CANCELLED;
1361
1362         cu->lastsel= NULL;
1363
1364         nu= editnurb->first;
1365         while(nu) {
1366                 next= nu->next;
1367
1368                 /* is entire nurb selected */
1369                 bp= nu->bp;
1370                 a= nu->pntsu*nu->pntsv;
1371                 while(a) {
1372                         a--;
1373                         if(bp->f1 & flag);
1374                         else break;
1375                         bp++;
1376                 }
1377                 if(a==0) {
1378                         BLI_remlink(editnurb, nu);
1379                         keyIndex_delNurb(cu->editnurb, nu);
1380                         freeNurb(nu); nu=NULL;
1381                 }
1382                 else {
1383                         /* is nurb in U direction selected */
1384                         newv= nu->pntsv;
1385                         bp= nu->bp;
1386                         for(b=0; b<nu->pntsv; b++) {
1387                                 sel= 0;
1388                                 for(a=0; a<nu->pntsu; a++, bp++) {
1389                                         if(bp->f1 & flag) sel++;
1390                                 }
1391                                 if(sel==nu->pntsu) {
1392                                         newv--;
1393                                 }
1394                                 else if(sel>=1) {
1395                                         /* don't delete */
1396                                         break;
1397                                 }
1398                         }
1399                         if(newv!=nu->pntsv && b==nu->pntsv)     {
1400                                 /* delete */
1401                                 bp= nu->bp;
1402                                 bpn = newbp =
1403                                         (BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
1404                                 for(b=0; b<nu->pntsv; b++) {
1405                                         if((bp->f1 & flag)==0) {
1406                                                 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
1407                                                 bpn+= nu->pntsu;
1408                                         } else {
1409                                                 keyIndex_delBP(cu->editnurb, bp);
1410                                         }
1411                                         bp+= nu->pntsu;
1412                                 }
1413                                 nu->pntsv= newv;
1414                                 keyIndex_updateBP(cu->editnurb, nu->bp, newbp, newv * nu->pntsu, 1);
1415                                 MEM_freeN(nu->bp);
1416                                 nu->bp= newbp;
1417                                 clamp_nurb_order_v(nu);
1418
1419                                 makeknots(nu, 2);
1420                         }
1421                         else {
1422                                 /* is the nurb in V direction selected */
1423                                 newu= nu->pntsu;
1424                                 for(a=0; a<nu->pntsu; a++) {
1425                                         bp= nu->bp+a;
1426                                         sel= 0;
1427                                         for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
1428                                                 if(bp->f1 & flag) sel++;
1429                                         }
1430                                         if(sel==nu->pntsv) {
1431                                                 newu--;
1432                                         }
1433                                         else if(sel>=1) {
1434                                                 /* don't delete */
1435                                                 break;
1436                                         }
1437                                 }
1438                                 if(newu!=nu->pntsu && a==nu->pntsu)     {
1439                                         /* delete */
1440                                         bp= nu->bp;
1441                                         bpn = newbp =
1442                                                 (BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
1443                                         for(b=0; b<nu->pntsv; b++) {
1444                                                 for(a=0; a<nu->pntsu; a++, bp++) {
1445                                                         if((bp->f1 & flag)==0) {
1446                                                                 *bpn= *bp;
1447                                                                 bpn++;
1448                                                         } else {
1449                                                                 keyIndex_delBP(cu->editnurb, bp);
1450                                                         }
1451                                                 }
1452                                         }
1453                                         keyIndex_updateBP(cu->editnurb, nu->bp, newbp, newu * nu->pntsv, 1);
1454                                         MEM_freeN(nu->bp);
1455                                         nu->bp= newbp;
1456                                         if(newu==1 && nu->pntsv>1) {    /* make a U spline */
1457                                                 nu->pntsu= nu->pntsv;
1458                                                 nu->pntsv= 1;
1459                                                 SWAP(short, nu->orderu, nu->orderv);
1460                                                 clamp_nurb_order_u(nu);
1461                                                 if(nu->knotsv) MEM_freeN(nu->knotsv);
1462                                                 nu->knotsv= NULL;
1463                                         }
1464                                         else {
1465                                                 nu->pntsu= newu;
1466                                                 clamp_nurb_order_u(nu);
1467                                         }
1468                                         makeknots(nu, 1);
1469                                 }
1470                         }
1471                 }
1472                 nu= next;
1473         }
1474
1475         return OPERATOR_FINISHED;
1476 }
1477
1478 /* only for OB_SURF */
1479 static short extrudeflagNurb(EditNurb *editnurb, int flag)
1480 {
1481         Nurb *nu;
1482         BPoint *bp, *bpn, *newbp;
1483         int ok= 0, a, u, v, len;
1484
1485         nu= editnurb->nurbs.first;
1486         while(nu) {
1487
1488                 if(nu->pntsv==1) {
1489                         bp= nu->bp;
1490                         a= nu->pntsu;
1491                         while(a) {
1492                                 if(bp->f1 & flag);
1493                                 else break;
1494                                 bp++;
1495                                 a--;
1496                         }
1497                         if(a==0) {
1498                                 ok= 1;
1499                                 newbp =
1500                                         (BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
1501                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
1502                                 bp= newbp+ nu->pntsu;
1503                                 ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu);
1504                                 MEM_freeN(nu->bp);
1505                                 nu->bp= newbp;
1506                                 a= nu->pntsu;
1507                                 while(a--) {
1508                                         select_bpoint(bp, SELECT, flag, HIDDEN);
1509                                         select_bpoint(newbp, DESELECT, flag, HIDDEN);
1510                                         bp++; 
1511                                         newbp++;
1512                                 }
1513
1514                                 nu->pntsv= 2;
1515                                 nu->orderv= 2;
1516                                 makeknots(nu, 2);
1517                         }
1518                 }
1519                 else {
1520                         /* which row or column is selected */
1521
1522                         if( isNurbselUV(nu, &u, &v, flag) ) {
1523
1524                                 /* deselect all */
1525                                 bp= nu->bp;
1526                                 a= nu->pntsu*nu->pntsv;
1527                                 while(a--) {
1528                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
1529                                         bp++;
1530                                 }
1531
1532                                 if(u==0 || u== nu->pntsv-1) {       /* row in u-direction selected */
1533                                         ok= 1;
1534                                         newbp =
1535                                                 (BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1)
1536                                                                                   * sizeof(BPoint), "extrudeNurb1");
1537                                         if(u==0) {
1538                                                 len= nu->pntsv*nu->pntsu;
1539                                                 ED_curve_bpcpy(editnurb, newbp+nu->pntsu, nu->bp, len);
1540                                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
1541                                                 bp= newbp;
1542                                         }
1543                                         else {
1544                                                 len= nu->pntsv*nu->pntsu;
1545                                                 ED_curve_bpcpy(editnurb, newbp, nu->bp, len);
1546                                                 ED_curve_bpcpy(editnurb, newbp+len, nu->bp+len-nu->pntsu, nu->pntsu);
1547                                                 bp= newbp+len;
1548                                         }
1549
1550                                         a= nu->pntsu;
1551                                         while(a--) {
1552                                                 select_bpoint(bp, SELECT, flag, HIDDEN);
1553                                                 bp++;
1554                                         }
1555
1556                                         MEM_freeN(nu->bp);
1557                                         nu->bp= newbp;
1558                                         nu->pntsv++;
1559                                         makeknots(nu, 2);
1560                                 }
1561                                 else if(v==0 || v== nu->pntsu-1) {          /* collumn in v-direction selected */
1562                                         ok= 1;
1563                                         bpn = newbp =
1564                                                 (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
1565                                         bp= nu->bp;
1566
1567                                         for(a=0; a<nu->pntsv; a++) {
1568                                                 if(v==0) {
1569                                                         *bpn= *bp;
1570                                                         bpn->f1 |= flag;
1571                                                         bpn++;
1572                                                 }
1573                                                 ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu);
1574                                                 bp+= nu->pntsu;
1575                                                 bpn+= nu->pntsu;
1576                                                 if(v== nu->pntsu-1) {
1577                                                         *bpn= *(bp-1);
1578                                                         bpn->f1 |= flag;
1579                                                         bpn++;
1580                                                 }
1581                                         }
1582
1583                                         MEM_freeN(nu->bp);
1584                                         nu->bp= newbp;
1585                                         nu->pntsu++;
1586                                         makeknots(nu, 1);
1587                                 }
1588                         }
1589                 }
1590                 nu= nu->next;
1591         }
1592
1593         return ok;
1594 }
1595
1596 static void adduplicateflagNurb(Object *obedit, short flag)
1597 {
1598         ListBase *editnurb= curve_get_editcurve(obedit);
1599         Nurb *nu, *newnu;
1600         BezTriple *bezt, *bezt1;
1601         BPoint *bp, *bp1;
1602         Curve *cu= (Curve*)obedit->data;
1603         int a, b, starta, enda, newu, newv;
1604         char *usel;
1605
1606         cu->lastsel= NULL;
1607
1608         nu= editnurb->last;
1609         while(nu) {
1610                 if(nu->type == CU_BEZIER) {
1611                         bezt= nu->bezt;
1612                         for(a=0; a<nu->pntsu; a++) {
1613                                 enda= -1;
1614                                 starta= a;
1615                                 while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
1616                                         select_beztriple(bezt, DESELECT, flag, HIDDEN);
1617                                         enda=a;
1618                                         if(a>=nu->pntsu-1) break;
1619                                         a++;
1620                                         bezt++;
1621                                 }
1622                                 if(enda>=starta) {
1623                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");  
1624                                         memcpy(newnu, nu, sizeof(Nurb));
1625                                         BLI_addtail(editnurb, newnu);
1626                                         set_actNurb(obedit, newnu);
1627                                         newnu->pntsu= enda-starta+1;
1628                                         newnu->bezt=
1629                                                 (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");  
1630                                         memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
1631
1632                                         b= newnu->pntsu;
1633                                         bezt1= newnu->bezt;
1634                                         while(b--) {
1635                                                 select_beztriple(bezt1, SELECT, flag, HIDDEN);
1636                                                 bezt1++;
1637                                         }
1638
1639                                         if(nu->flagu & CU_NURB_CYCLIC) {
1640                                                 if(starta!=0 || enda!=nu->pntsu-1) {
1641                                                         newnu->flagu &= ~CU_NURB_CYCLIC;
1642                                                 }
1643                                         }
1644                                 }
1645                                 bezt++;
1646                         }
1647                 }
1648                 else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
1649                         bp= nu->bp;
1650                         for(a=0; a<nu->pntsu; a++) {
1651                                 enda= -1;
1652                                 starta= a;
1653                                 while(bp->f1 & flag) {
1654                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
1655                                         enda= a;
1656                                         if(a>=nu->pntsu-1) break;
1657                                         a++;
1658                                         bp++;
1659                                 }
1660                                 if(enda>=starta) {
1661                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");  
1662                                         memcpy(newnu, nu, sizeof(Nurb));
1663                                         set_actNurb(obedit, newnu);
1664                                         BLI_addtail(editnurb, newnu);
1665                                         newnu->pntsu= enda-starta+1;
1666                                         newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
1667                                         memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
1668
1669                                         b= newnu->pntsu;
1670                                         bp1= newnu->bp;
1671                                         while(b--) {
1672                                                 select_bpoint(bp1, SELECT, flag, HIDDEN);
1673                                                 bp1++;
1674                                         }
1675
1676                                         if(nu->flagu & CU_NURB_CYCLIC) {
1677                                                 if(starta!=0 || enda!=nu->pntsu-1) {
1678                                                         newnu->flagu &= ~CU_NURB_CYCLIC;
1679                                                 }
1680                                         }
1681
1682                                         /* knots */
1683                                         newnu->knotsu= NULL;
1684                                         makeknots(newnu, 1);
1685                                 }
1686                                 bp++;
1687                         }
1688                 }
1689                 else {
1690                         /* a rectangular area in nurb has to be selected */
1691                         if(isNurbsel(nu)) {
1692                                 usel= MEM_callocN(nu->pntsu, "adduplicateN4");
1693                                 bp= nu->bp;
1694                                 for(a=0; a<nu->pntsv; a++) {
1695                                         for(b=0; b<nu->pntsu; b++, bp++) {
1696                                                 if(bp->f1 & flag) usel[b]++;
1697                                         }
1698                                 }
1699                                 newu= 0;
1700                                 newv= 0;
1701                                 for(a=0; a<nu->pntsu; a++) {
1702                                         if(usel[a]) {
1703                                                 if(newv==0 || usel[a]==newv) {
1704                                                         newv= usel[a];
1705                                                         newu++;
1706                                                 }
1707                                                 else {
1708                                                         newv= 0;
1709                                                         break;
1710                                                 }
1711                                         }
1712                                 }
1713                                 if(newu==0 || newv==0) {
1714                                         if (G.f & G_DEBUG)
1715                                                 printf("Can't duplicate Nurb\n");
1716                                 }
1717                                 else {
1718
1719                                         if(newu==1) SWAP(short, newu, newv);
1720
1721                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
1722                                         memcpy(newnu, nu, sizeof(Nurb));
1723                                         BLI_addtail(editnurb, newnu);
1724                                         set_actNurb(obedit, newnu);
1725                                         newnu->pntsu= newu;
1726                                         newnu->pntsv= newv;
1727                                         newnu->bp =
1728                                                 (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
1729                                         clamp_nurb_order_u(newnu);
1730                                         clamp_nurb_order_v(newnu);
1731                                         
1732                                         newnu->knotsu= newnu->knotsv= NULL;
1733                                         
1734                                         bp= newnu->bp;
1735                                         bp1= nu->bp;
1736                                         for(a=0; a<nu->pntsv; a++) {
1737                                                 for(b=0; b<nu->pntsu; b++, bp1++) {
1738                                                         if(bp1->f1 & flag) {
1739                                                                 memcpy(bp, bp1, sizeof(BPoint));
1740                                                                 select_bpoint(bp1, DESELECT, flag, HIDDEN);
1741                                                                 bp++;
1742                                                         }
1743                                                 }
1744                                         }
1745                                         if (check_valid_nurb_u(newnu)) {
1746                                                 if(nu->pntsu==newnu->pntsu && nu->knotsu) {
1747                                                         newnu->knotsu= MEM_dupallocN( nu->knotsu );
1748                                                 } else {
1749                                                         makeknots(newnu, 1);
1750                                                 }
1751                                         }
1752                                         if (check_valid_nurb_v(newnu)) {
1753                                                 if(nu->pntsv==newnu->pntsv && nu->knotsv) {
1754                                                         newnu->knotsv= MEM_dupallocN( nu->knotsv );
1755                                                 } else {
1756                                                         makeknots(newnu, 2);
1757                                                 }
1758                                         }
1759                                 }
1760                                 MEM_freeN(usel);
1761                         }
1762                 }
1763
1764                 nu= nu->prev;
1765         }
1766         
1767         /* actnu changed */
1768 }
1769
1770 /**************** switch direction operator ***************/
1771
1772 static int switch_direction_exec(bContext *C, wmOperator *op)
1773 {
1774         Object *obedit= CTX_data_edit_object(C);
1775         Curve *cu= (Curve*)obedit->data;
1776         EditNurb *editnurb= cu->editnurb;
1777         Nurb *nu;
1778
1779         for(nu= editnurb->nurbs.first; nu; nu= nu->next)
1780                 if(isNurbsel(nu)) {
1781                         switchdirectionNurb(nu);
1782                         keyData_switchDirectionNurb(cu, nu);
1783                 }
1784
1785         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1786         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1787
1788         return OPERATOR_FINISHED;
1789 }
1790
1791 void CURVE_OT_switch_direction(wmOperatorType *ot)
1792 {
1793         /* identifiers */
1794         ot->name= "Switch Direction";
1795         ot->idname= "CURVE_OT_switch_direction";
1796         
1797         /* api callbacks */
1798         ot->exec= switch_direction_exec;
1799         ot->poll= ED_operator_editsurfcurve;
1800
1801         /* flags */
1802         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1803 }
1804
1805 /****************** set weight operator *******************/
1806
1807 static int set_weight_exec(bContext *C, wmOperator *op)
1808 {
1809         Object *obedit= CTX_data_edit_object(C);
1810         ListBase *editnurb= curve_get_editcurve(obedit);
1811         Nurb *nu;
1812         BezTriple *bezt;
1813         BPoint *bp;
1814         float weight= RNA_float_get(op->ptr, "weight");
1815         int a;
1816                                 
1817         for(nu= editnurb->first; nu; nu= nu->next) {
1818                 if(nu->bezt) {
1819                         for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1820                                 if(bezt->f2 & SELECT)
1821                                         bezt->weight= weight;
1822                         }
1823                 }
1824                 else if(nu->bp) {
1825                         for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1826                                 if(bp->f1 & SELECT)
1827                                         bp->weight= weight;
1828                         }
1829                 }
1830         }       
1831
1832         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1833         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1834
1835         return OPERATOR_FINISHED;
1836 }
1837
1838 void CURVE_OT_spline_weight_set(wmOperatorType *ot)
1839 {
1840         /* identifiers */
1841         ot->name= "Set Curve Weight";
1842         ot->idname= "CURVE_OT_spline_weight_set";
1843         
1844         /* api callbacks */
1845         ot->exec= set_weight_exec;
1846         ot->invoke= WM_operator_props_popup;
1847         ot->poll= ED_operator_editsurfcurve;
1848
1849         /* flags */
1850         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1851
1852         /* properties */
1853         RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
1854 }
1855
1856 /******************* set radius operator ******************/
1857
1858 static int set_radius_exec(bContext *C, wmOperator *op)
1859 {
1860         Object *obedit= CTX_data_edit_object(C);
1861         ListBase *editnurb= curve_get_editcurve(obedit);
1862         Nurb *nu;
1863         BezTriple *bezt;
1864         BPoint *bp;
1865         float radius= RNA_float_get(op->ptr, "radius");
1866         int a;
1867         
1868         for(nu= editnurb->first; nu; nu= nu->next) {
1869                 if(nu->bezt) {
1870                         for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1871                                 if(bezt->f2 & SELECT)
1872                                         bezt->radius= radius;
1873                         }
1874                 }
1875                 else if(nu->bp) {
1876                         for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1877                                 if(bp->f1 & SELECT)
1878                                         bp->radius= radius;
1879                         }
1880                 }
1881         }       
1882
1883         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1884         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1885
1886         return OPERATOR_FINISHED;
1887 }
1888
1889 void CURVE_OT_radius_set(wmOperatorType *ot)
1890 {
1891         /* identifiers */
1892         ot->name= "Set Curve Radius";
1893         ot->idname= "CURVE_OT_radius_set";
1894         
1895         /* api callbacks */
1896         ot->exec= set_radius_exec;
1897         ot->invoke= WM_operator_props_popup;
1898         ot->poll= ED_operator_editsurfcurve;
1899
1900         /* flags */
1901         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1902
1903         /* properties */
1904         RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "", 0.0001f, 10.0f);
1905 }
1906
1907 /********************* smooth operator ********************/
1908
1909 static int smooth_exec(bContext *C, wmOperator *op)
1910 {
1911         Object *obedit= CTX_data_edit_object(C);
1912         ListBase *editnurb= curve_get_editcurve(obedit);
1913         Nurb *nu;
1914         BezTriple *bezt, *beztOrig;
1915         BPoint *bp, *bpOrig;
1916         float val, newval, offset;
1917         int a, i, change = 0;
1918         
1919         for(nu= editnurb->first; nu; nu= nu->next) {
1920                 if(nu->bezt) {
1921                         change = 0;
1922                         beztOrig = MEM_dupallocN( nu->bezt );
1923                         for(bezt=nu->bezt+1, a=1; a<nu->pntsu-1; a++, bezt++) {
1924                                 if(bezt->f2 & SELECT) {
1925                                         for(i=0; i<3; i++) {
1926                                                 val = bezt->vec[1][i];
1927                                                 newval = ((beztOrig+(a-1))->vec[1][i] * 0.5) + ((beztOrig+(a+1))->vec[1][i] * 0.5);
1928                                                 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1929                                                 /* offset handles */
1930                                                 bezt->vec[1][i] += offset;
1931                                                 bezt->vec[0][i] += offset;
1932                                                 bezt->vec[2][i] += offset;
1933                                         }
1934                                         change = 1;
1935                                 }
1936                         }
1937                         MEM_freeN(beztOrig);
1938                         if (change)
1939                                 calchandlesNurb(nu);
1940                 } else if (nu->bp) {
1941                         bpOrig = MEM_dupallocN( nu->bp );
1942                         /* Same as above, keep these the same! */
1943                         for(bp=nu->bp+1, a=1; a<nu->pntsu-1; a++, bp++) {
1944                                 if(bp->f1 & SELECT) {
1945                                         for(i=0; i<3; i++) {
1946                                                 val = bp->vec[i];
1947                                                 newval = ((bpOrig+(a-1))->vec[i] * 0.5) + ((bpOrig+(a+1))->vec[i] * 0.5);
1948                                                 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1949                                         
1950                                                 bp->vec[i] += offset;
1951                                         }
1952                                 }
1953                         }
1954                         MEM_freeN(bpOrig);
1955                 }
1956         }
1957
1958         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1959         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
1960
1961         return OPERATOR_FINISHED;
1962 }
1963
1964 void CURVE_OT_smooth(wmOperatorType *ot)
1965 {
1966         /* identifiers */
1967         ot->name= "Smooth";
1968         ot->idname= "CURVE_OT_smooth";
1969         
1970         /* api callbacks */
1971         ot->exec= smooth_exec;
1972         ot->poll= ED_operator_editsurfcurve;
1973
1974         /* flags */
1975         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1976 }
1977
1978 /**************** smooth curve radius operator *************/
1979
1980 /* TODO, make smoothing distance based */
1981 static int smooth_radius_exec(bContext *C, wmOperator *op)
1982 {
1983         Object *obedit= CTX_data_edit_object(C);
1984         ListBase *editnurb= curve_get_editcurve(obedit);
1985         Nurb *nu;
1986         BezTriple *bezt;
1987         BPoint *bp;
1988         int a;
1989         
1990         /* use for smoothing */
1991         int last_sel;
1992         int start_sel, end_sel; /* selection indicies, inclusive */
1993         float start_rad, end_rad, fac, range;
1994         
1995         for(nu= editnurb->first; nu; nu= nu->next) {
1996                 if(nu->bezt) {
1997                         
1998                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1999                                 /* loop over selection segments of a curve, smooth each */
2000                                 
2001                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
2002                                 start_sel = end_sel = -1;
2003                                 for(bezt=nu->bezt+last_sel, a=last_sel; a<nu->pntsu; a++, bezt++) {
2004                                         if(bezt->f2 & SELECT) {
2005                                                 start_sel = a;
2006                                                 break;
2007                                         }
2008                                 }
2009                                 /* incase there are no other selected verts */
2010                                 end_sel = start_sel;
2011                                 for(bezt=nu->bezt+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bezt++) {
2012                                         if((bezt->f2 & SELECT)==0) {
2013                                                 break;
2014                                         }
2015                                         end_sel = a;
2016                                 }
2017                                 
2018                                 if (start_sel == -1) {
2019                                         last_sel = nu->pntsu; /* next... */
2020                                 } else {
2021                                         last_sel = end_sel; /* before we modify it */
2022                                         
2023                                         /* now blend between start and end sel */
2024                                         start_rad = end_rad = -1.0;
2025                                         
2026                                         if (start_sel == end_sel) {
2027                                                 /* simple, only 1 point selected */
2028                                                 if (start_sel>0)                                                start_rad = (nu->bezt+start_sel-1)->radius;
2029                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bezt+start_sel+1)->radius;
2030                                                 
2031                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bezt+start_sel)->radius = (start_rad + end_rad)/2;
2032                                                 else if (start_rad >= 0.0)                              (nu->bezt+start_sel)->radius = start_rad;
2033                                                 else if (end_rad >= 0.0)                                (nu->bezt+start_sel)->radius = end_rad;
2034                                         } else {
2035                                                 /* if endpoints selected, then use them */
2036                                                 if (start_sel==0) {
2037                                                         start_rad = (nu->bezt+start_sel)->radius;
2038                                                         start_sel++; /* we dont want to edit the selected endpoint */
2039                                                 } else {
2040                                                         start_rad = (nu->bezt+start_sel-1)->radius;
2041                                                 }
2042                                                 if (end_sel==nu->pntsu-1) {
2043                                                         end_rad = (nu->bezt+end_sel)->radius;
2044                                                         end_sel--; /* we dont want to edit the selected endpoint */
2045                                                 } else {
2046                                                         end_rad = (nu->bezt+end_sel+1)->radius;
2047                                                 }
2048                                                 
2049                                                 /* Now Blend between the points */
2050                                                 range = (float)(end_sel - start_sel) + 2.0f;
2051                                                 for(bezt=nu->bezt+start_sel, a=start_sel; a<=end_sel; a++, bezt++) {
2052                                                         fac = (float)(1+a-start_sel) / range;
2053                                                         bezt->radius = start_rad*(1.0-fac) + end_rad*fac;
2054                                                 }
2055                                         }
2056                                 }
2057                         }
2058                 } else if (nu->bp) {
2059                         /* Same as above, keep these the same! */
2060                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
2061                                 /* loop over selection segments of a curve, smooth each */
2062                                 
2063                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
2064                                 start_sel = end_sel = -1;
2065                                 for(bp=nu->bp+last_sel, a=last_sel; a<nu->pntsu; a++, bp++) {
2066                                         if(bp->f1 & SELECT) {
2067                                                 start_sel = a;
2068                                                 break;
2069                                         }
2070                                 }
2071                                 /* incase there are no other selected verts */
2072                                 end_sel = start_sel;
2073                                 for(bp=nu->bp+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bp++) {
2074                                         if((bp->f1 & SELECT)==0) {
2075                                                 break;
2076                                         }
2077                                         end_sel = a;
2078                                 }
2079                                 
2080                                 if (start_sel == -1) {
2081                                         last_sel = nu->pntsu; /* next... */
2082                                 } else {
2083                                         last_sel = end_sel; /* before we modify it */
2084                                         
2085                                         /* now blend between start and end sel */
2086                                         start_rad = end_rad = -1.0;
2087                                         
2088                                         if (start_sel == end_sel) {
2089                                                 /* simple, only 1 point selected */
2090                                                 if (start_sel>0)                                                start_rad = (nu->bp+start_sel-1)->radius;
2091                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bp+start_sel+1)->radius;
2092                                                 
2093                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bp+start_sel)->radius = (start_rad + end_rad)/2;
2094                                                 else if (start_rad >= 0.0)                              (nu->bp+start_sel)->radius = start_rad;
2095                                                 else if (end_rad >= 0.0)                                (nu->bp+start_sel)->radius = end_rad;
2096                                         } else {
2097                                                 /* if endpoints selected, then use them */
2098                                                 if (start_sel==0) {
2099                                                         start_rad = (nu->bp+start_sel)->radius;
2100                                                         start_sel++; /* we dont want to edit the selected endpoint */
2101                                                 } else {
2102                                                         start_rad = (nu->bp+start_sel-1)->radius;
2103                                                 }
2104                                                 if (end_sel==nu->pntsu-1) {
2105                                                         end_rad = (nu->bp+end_sel)->radius;
2106                                                         end_sel--; /* we dont want to edit the selected endpoint */
2107                                                 } else {
2108                                                         end_rad = (nu->bp+end_sel+1)->radius;
2109                                                 }
2110                                                 
2111                                                 /* Now Blend between the points */
2112                                                 range = (float)(end_sel - start_sel) + 2.0f;
2113                                                 for(bp=nu->bp+start_sel, a=start_sel; a<=end_sel; a++, bp++) {
2114                                                         fac = (float)(1+a-start_sel) / range;
2115                                                         bp->radius = start_rad*(1.0-fac) + end_rad*fac;
2116                                                 }
2117                                         }
2118                                 }
2119                         }
2120                 }
2121         }
2122
2123         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2124         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2125
2126         return OPERATOR_FINISHED;
2127 }
2128
2129 void CURVE_OT_smooth_radius(wmOperatorType *ot)
2130 {
2131         /* identifiers */
2132         ot->name= "Smooth Curve Radius";
2133         ot->idname= "CURVE_OT_smooth_radius";
2134         
2135         /* api clastbacks */
2136         ot->exec= smooth_radius_exec;
2137         ot->poll= ED_operator_editsurfcurve;
2138         
2139         /* flags */
2140         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2141 }
2142
2143 /***************** selection utility *************************/
2144
2145 /* next == 1 -> select next             */
2146 /* next == -1 -> select previous        */
2147 /* cont == 1 -> select continuously     */
2148 /* selstatus, inverts behaviour         */
2149 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus)
2150 {
2151         Nurb *nu;
2152         BezTriple *bezt;
2153         BPoint *bp;
2154         int a;
2155         short lastsel= 0, sel=0;
2156         
2157         if(next==0) return;
2158         
2159         for(nu= editnurb->first; nu; nu= nu->next) {
2160                 lastsel=0;
2161                 if(nu->type == CU_BEZIER) {                     
2162                         a= nu->pntsu;
2163                         bezt= nu->bezt;
2164                         if(next < 0) bezt= (nu->bezt + (a-1));
2165                         while(a--) {
2166                                 if(a-abs(next) < 0) break;
2167                                 sel= 0;
2168                                 if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & SELECT) || (selstatus==0))) {
2169                                         bezt+=next;
2170                                         if(!(bezt->f2 & SELECT) || (selstatus==0)) {
2171                                                 sel= select_beztriple(bezt, selstatus, 1, VISIBLE);     
2172                                                 if((sel==1) && (cont==0)) lastsel= 1;
2173                                         }                                                       
2174                                 }
2175                                 else {
2176                                         bezt+=next;
2177                                         lastsel= 0;
2178                                 }
2179                                 /* move around in zigzag way so that we go through each */                              
2180                                 bezt-=(next-next/abs(next));                            
2181                         }
2182                 }
2183                 else {
2184                         a= nu->pntsu*nu->pntsv;
2185                         bp= nu->bp;
2186                         if(next < 0) bp= (nu->bp + (a-1));
2187                         while(a--) {
2188                                 if(a-abs(next) < 0) break;
2189                                 sel=0;
2190                                 if((lastsel==0) && (bp->hide==0) && ((bp->f1 & SELECT) || (selstatus==0))) {
2191                                         bp+=next;
2192                                         if(!(bp->f1 & SELECT) || (selstatus==0)) {
2193                                                 sel= select_bpoint(bp, selstatus, 1, VISIBLE);
2194                                                 if((sel==1) && (cont==0)) lastsel= 1;
2195                                         }                       
2196                                 }
2197                                 else {
2198                                         bp+=next;
2199                                         lastsel= 0;
2200                                 }
2201                                 /* move around in zigzag way so that we go through each */
2202                                 bp-=(next-next/abs(next));                              
2203                         }
2204                 }
2205         }
2206 }
2207
2208 /**************** select start/end operators **************/
2209
2210 /* (de)selects first or last of visible part of each Nurb depending on selFirst     */
2211 /* selFirst: defines the end of which to select                                     */
2212 /* doswap: defines if selection state of each first/last control point is swapped   */
2213 /* selstatus: selection status in case doswap is false                              */
2214 void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus)
2215 {
2216         ListBase *editnurb= curve_get_editcurve(obedit);
2217         Nurb *nu;
2218         BPoint *bp;
2219         BezTriple *bezt;
2220         Curve *cu;
2221         int a;
2222         short sel;
2223
2224         if(obedit==0) return;
2225
2226         cu= (Curve*)obedit->data;
2227         cu->lastsel= NULL;
2228
2229         for(nu= editnurb->first; nu; nu= nu->next) {
2230                 sel= 0;
2231                 if(nu->type == CU_BEZIER) {
2232                         a= nu->pntsu;
2233                         
2234                         /* which point? */
2235                         if(selfirst==0) { /* select last */ 
2236                                 bezt= (nu->bezt + (a-1));
2237                         }
2238                         else { /* select first */
2239                                 bezt= nu->bezt;
2240                         }
2241                         
2242                         while(a--) {
2243                                 if(doswap) sel= swap_selection_beztriple(bezt);
2244                                 else sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
2245                                 
2246                                 if(sel==1) break;
2247                         }
2248                 }
2249                 else {
2250                         a= nu->pntsu*nu->pntsv;
2251                         
2252                         /* which point? */
2253                         if(selfirst==0) { /* select last */
2254                                 bp= (nu->bp + (a-1));
2255                         }
2256                         else{ /* select first */
2257                                 bp= nu->bp;
2258                         }
2259
2260                         while(a--) {
2261                                 if (bp->hide == 0) {
2262                                         if(doswap) sel= swap_selection_bpoint(bp);
2263                                         else sel= select_bpoint(bp, selstatus, 1, VISIBLE);
2264                                         
2265                                         if(sel==1) break;
2266                                 }
2267                         }
2268                 }
2269         }
2270 }
2271
2272 static int de_select_first_exec(bContext *C, wmOperator *op)
2273 {
2274         Object *obedit= CTX_data_edit_object(C);
2275
2276         selectend_nurb(obedit, FIRST, 1, DESELECT);
2277         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2278
2279         return OPERATOR_FINISHED;
2280 }
2281
2282 void CURVE_OT_de_select_first(wmOperatorType *ot)
2283 {
2284         /* identifiers */
2285         ot->name= "Select or Deselect First";
2286         ot->idname= "CURVE_OT_de_select_first";
2287         
2288         /* api cfirstbacks */
2289         ot->exec= de_select_first_exec;
2290         ot->poll= ED_operator_editcurve;
2291         
2292         /* flags */
2293         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2294 }
2295
2296 static int de_select_last_exec(bContext *C, wmOperator *op)
2297 {
2298         Object *obedit= CTX_data_edit_object(C);
2299
2300         selectend_nurb(obedit, LAST, 1, DESELECT);
2301         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2302
2303         return OPERATOR_FINISHED;
2304 }
2305
2306 void CURVE_OT_de_select_last(wmOperatorType *ot)
2307 {
2308         /* identifiers */
2309         ot->name= "Select or Deselect Last";
2310         ot->idname= "CURVE_OT_de_select_last";
2311         
2312         /* api clastbacks */
2313         ot->exec= de_select_last_exec;
2314         ot->poll= ED_operator_editcurve;
2315         
2316         /* flags */
2317         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2318 }
2319
2320 /******************* de select all operator ***************/
2321
2322 static short nurb_has_selected_cps(ListBase *editnurb)
2323 {
2324         Nurb *nu;
2325         BezTriple *bezt;
2326         BPoint *bp;
2327         int a;
2328
2329         for(nu= editnurb->first; nu; nu= nu->next) {
2330                 if(nu->type == CU_BEZIER) {
2331                         a= nu->pntsu;
2332                         bezt= nu->bezt;
2333                         while(a--) {
2334                                 if(bezt->hide==0) {
2335                                         if((bezt->f1 & SELECT)
2336                                         || (bezt->f2 & SELECT)
2337                                         || (bezt->f3 & SELECT)) return 1;
2338                                 }
2339                                 bezt++;
2340                         }
2341                 }
2342                 else {
2343                         a= nu->pntsu*nu->pntsv;
2344                         bp= nu->bp;
2345                         while(a--) {
2346                                 if((bp->hide==0) && (bp->f1 & SELECT)) return 1;
2347                                 bp++;
2348                         }
2349                 }
2350         }
2351         
2352         return 0;
2353 }
2354
2355 static int de_select_all_exec(bContext *C, wmOperator *op)
2356 {
2357         Object *obedit= CTX_data_edit_object(C);
2358         ListBase *editnurb= curve_get_editcurve(obedit);
2359         int action = RNA_enum_get(op->ptr, "action");
2360
2361         if (action == SEL_TOGGLE) {
2362                 action = SEL_SELECT;
2363                 if(nurb_has_selected_cps(editnurb))
2364                         action = SEL_DESELECT;
2365         }
2366
2367         switch (action) {
2368                 case SEL_SELECT:
2369                         CU_select_all(obedit);
2370                         break;
2371                 case SEL_DESELECT:
2372                         CU_deselect_all(obedit);
2373                         break;
2374                 case SEL_INVERT:
2375                         CU_select_swap(obedit);
2376                         break;
2377         }
2378         
2379         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2380
2381         return OPERATOR_FINISHED;
2382 }
2383
2384 void CURVE_OT_select_all(wmOperatorType *ot)
2385 {
2386         /* identifiers */
2387         ot->name= "Select or Deselect All";
2388         ot->idname= "CURVE_OT_select_all";
2389         
2390         /* api callbacks */
2391         ot->exec= de_select_all_exec;
2392         ot->poll= ED_operator_editsurfcurve;
2393         
2394         /* flags */
2395         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2396
2397         /* properties */
2398         WM_operator_properties_select_all(ot);
2399 }
2400
2401 /********************** hide operator *********************/
2402
2403 static int hide_exec(bContext *C, wmOperator *op)
2404 {
2405         Object *obedit= CTX_data_edit_object(C);
2406         Curve *cu= obedit->data;
2407         ListBase *editnurb= curve_get_editcurve(obedit);
2408         Nurb *nu;
2409         BPoint *bp;
2410         BezTriple *bezt;
2411         int a, sel, invert= RNA_boolean_get(op->ptr, "unselected");
2412
2413         for(nu= editnurb->first; nu; nu= nu->next) {
2414                 if(nu->type == CU_BEZIER) {
2415                         bezt= nu->bezt;
2416                         a= nu->pntsu;
2417                         sel= 0;
2418                         while(a--) {
2419                                 if(invert == 0 && BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
2420                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
2421                                         bezt->hide= 1;
2422                                 }
2423                                 else if(invert && !BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
2424                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
2425                                         bezt->hide= 1;
2426                                 }
2427                                 if(bezt->hide) sel++;
2428                                 bezt++;
2429                         }
2430                         if(sel==nu->pntsu) nu->hide= 1;
2431                 }
2432                 else {
2433                         bp= nu->bp;
2434                         a= nu->pntsu*nu->pntsv;
2435                         sel= 0;
2436                         while(a--) {
2437                                 if(invert==0 && (bp->f1 & SELECT)) {
2438                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
2439                                         bp->hide= 1;
2440                                 }
2441                                 else if(invert && (bp->f1 & SELECT)==0) {
2442                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
2443                                         bp->hide= 1;
2444                                 }
2445                                 if(bp->hide) sel++;
2446                                 bp++;
2447                         }
2448                         if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
2449                 }
2450         }
2451
2452         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2453         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2454
2455         return OPERATOR_FINISHED;       
2456 }
2457
2458 void CURVE_OT_hide(wmOperatorType *ot)
2459 {
2460         /* identifiers */
2461         ot->name= "Hide Selected";
2462         ot->idname= "CURVE_OT_hide";
2463         
2464         /* api callbacks */
2465         ot->exec= hide_exec;
2466         ot->poll= ED_operator_editsurfcurve;
2467         
2468         /* flags */
2469         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2470         
2471         /* props */
2472         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
2473 }
2474
2475 /********************** reveal operator *********************/
2476
2477 static int reveal_exec(bContext *C, wmOperator *op)
2478 {
2479         Object *obedit= CTX_data_edit_object(C);
2480         ListBase *editnurb= curve_get_editcurve(obedit);
2481         Nurb *nu;
2482         BPoint *bp;
2483         BezTriple *bezt;
2484         int a;
2485
2486         for(nu= editnurb->first; nu; nu= nu->next) {
2487                 nu->hide= 0;
2488                 if(nu->type == CU_BEZIER) {
2489                         bezt= nu->bezt;
2490                         a= nu->pntsu;
2491                         while(a--) {
2492                                 if(bezt->hide) {
2493                                         select_beztriple(bezt, SELECT, 1, HIDDEN);
2494                                         bezt->hide= 0;
2495                                 }
2496                                 bezt++;
2497                         }
2498                 }
2499                 else {
2500                         bp= nu->bp;
2501                         a= nu->pntsu*nu->pntsv;
2502                         while(a--) {
2503                                 if(bp->hide) {
2504                                         select_bpoint(bp, SELECT, 1, HIDDEN);
2505                                         bp->hide= 0;
2506                                 }
2507                                 bp++;
2508                         }
2509                 }
2510         }
2511
2512         DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
2513         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2514
2515         return OPERATOR_FINISHED;       
2516 }
2517
2518 void CURVE_OT_reveal(wmOperatorType *ot)
2519 {
2520         /* identifiers */
2521         ot->name= "Reveal Hidden";
2522         ot->idname= "CURVE_OT_reveal";
2523         
2524         /* api callbacks */
2525         ot->exec= reveal_exec;
2526         ot->poll= ED_operator_editsurfcurve;
2527         
2528         /* flags */
2529         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2530 }
2531
2532 /********************** select invert operator *********************/
2533
2534 static int select_inverse_exec(bContext *C, wmOperator *op)
2535 {
2536         Object *obedit= CTX_data_edit_object(C);
2537         Curve *cu= obedit->data;
2538         ListBase *editnurb= curve_get_editcurve(obedit);
2539         Nurb *nu;
2540         BPoint *bp;
2541         BezTriple *bezt;
2542         int a;
2543
2544         cu->lastsel= NULL;
2545
2546         for(nu= editnurb->first; nu; nu= nu->next) {
2547                 if(nu->type == CU_BEZIER) {
2548                         bezt= nu->bezt;
2549                         a= nu->pntsu;
2550                         while(a--) {
2551                                 if(bezt->hide==0) {
2552                                         bezt->f2 ^= SELECT; /* always do the center point */
2553                                         if((cu->drawflag & CU_HIDE_HANDLES)==0) {
2554                                                 bezt->f1 ^= SELECT;
2555                                                 bezt->f3 ^= SELECT;
2556                                         }
2557                                 }
2558                                 bezt++;
2559                         }
2560                 }
2561                 else {
2562                         bp= nu->bp;
2563                         a= nu->pntsu*nu->pntsv;
2564                         while(a--) {
2565                                 swap_selection_bpoint(bp);
2566                                 bp++;
2567                         }
2568                 }
2569         }
2570
2571         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2572
2573         return OPERATOR_FINISHED;       
2574 }
2575
2576 void CURVE_OT_select_inverse(wmOperatorType *ot)
2577 {
2578         /* identifiers */
2579         ot->name= "Select Inverse";
2580         ot->idname= "CURVE_OT_select_inverse";
2581         
2582         /* api callbacks */
2583         ot->exec= select_inverse_exec;
2584         ot->poll= ED_operator_editsurfcurve;
2585         
2586         /* flags */
2587         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2588 }
2589
2590 /********************** subdivide operator *********************/
2591
2592 /** Divide the line segments associated with the currently selected
2593  * curve nodes (Bezier or NURB). If there are no valid segment
2594  * selections within the current selection, nothing happens.
2595  *
2596  * @deffunc subdividenurb subdivideNurb(void)
2597  * @return Nothing
2598  * @param  None
2599 */
2600
2601 static void subdividenurb(Object *obedit, int number_cuts)
2602 {
2603         Curve *cu= obedit->data;
2604         ListBase *editnurb= curve_get_editcurve(obedit);
2605         Nurb *nu;
2606         BezTriple *prevbezt, *bezt, *beztnew, *beztn;
2607         BPoint *bp, *prevbp, *bpnew, *bpn;
2608         float vec[15];
2609         int a, b, sel, amount, *usel, *vsel, i;
2610         float factor;
2611
2612    // printf("*** subdivideNurb: entering subdivide\n");
2613
2614         for(nu= editnurb->first; nu; nu= nu->next) {
2615                 amount= 0;
2616                 if(nu->type == CU_BEZIER) {
2617                 /* 
2618                    Insert a point into a 2D Bezier curve. 
2619                    Endpoints are preserved. Otherwise, all selected and inserted points are 
2620                    newly created. Old points are discarded.
2621                 */
2622                         /* count */
2623                         if(nu->flagu & CU_NURB_CYCLIC) {
2624                                 a= nu->pntsu;
2625                                 bezt= nu->bezt;
2626                                 prevbezt= bezt+(a-1);
2627                         }
2628                         else {
2629                                 a= nu->pntsu-1;
2630                                 prevbezt= nu->bezt;
2631                                 bezt= prevbezt+1;
2632                         }
2633                         while(a--) {
2634                                 if( BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) amount+=number_cuts;
2635                                 prevbezt= bezt;
2636                                 bezt++;
2637                         }
2638
2639                         if(amount) {
2640                                 /* insert */
2641                                 beztnew =
2642                                         (BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
2643                                 beztn= beztnew;
2644                                 if(nu->flagu & CU_NURB_CYCLIC) {
2645                                         a= nu->pntsu;
2646                                         bezt= nu->bezt;
2647                                         prevbezt= bezt+(a-1);
2648                                 }
2649                                 else {
2650                                         a= nu->pntsu-1;
2651                                         prevbezt= nu->bezt;
2652                                         bezt= prevbezt+1;
2653                                 }
2654                                 while(a--) {
2655                                         memcpy(beztn, prevbezt, sizeof(BezTriple));
2656                                         beztn++;
2657
2658                                         if( BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
2659                                                 float prevvec[3][3];
2660
2661                                                 memcpy(prevvec, prevbezt->vec, sizeof(float) * 9);
2662
2663                                                 for (i = 0; i < number_cuts; i++) {
2664                                                         factor = 1.0f / (number_cuts + 1 - i);
2665
2666                                                         memcpy(beztn, bezt, sizeof(BezTriple));
2667
2668                                                         /* midpoint subdividing */
2669                                                         interp_v3_v3v3(vec, prevvec[1], prevvec[2], factor);
2670                                                         interp_v3_v3v3(vec+3, prevvec[2], bezt->vec[0], factor);
2671                                                         interp_v3_v3v3(vec+6, bezt->vec[0], bezt->vec[1], factor);
2672
2673                                                         interp_v3_v3v3(vec+9, vec, vec+3, factor);
2674                                                         interp_v3_v3v3(vec+12, vec+3, vec+6, factor);
2675
2676                                                         /* change handle of prev beztn */
2677                                                         VECCOPY((beztn-1)->vec[2], vec);
2678                                                         /* new point */
2679                                                         VECCOPY(beztn->vec[0], vec+9);
2680                                                         interp_v3_v3v3(beztn->vec[1], vec+9, vec+12, factor);
2681                                                         VECCOPY(beztn->vec[2], vec+12);
2682                                                         /* handle of next bezt */
2683                                                         if(a==0 && i == number_cuts - 1 && (nu->flagu & CU_NURB_CYCLIC)) {VECCOPY(beztnew->vec[0], vec+6);}
2684                                                         else {VECCOPY(bezt->vec[0], vec+6);}
2685
2686                                                         beztn->radius = (prevbezt->radius + bezt->radius)/2;
2687                                                         beztn->weight = (prevbezt->weight + bezt->weight)/2;
2688
2689                                                         memcpy(prevvec, beztn->vec, sizeof(float) * 9);
2690                                                         beztn++;
2691                                                 }
2692                                         }
2693
2694                                         prevbezt= bezt;
2695                                         bezt++;
2696                                 }
2697                                 /* last point */
2698                                 if((nu->flagu & CU_NURB_CYCLIC)==0) memcpy(beztn, prevbezt, sizeof(BezTriple));
2699
2700                                 MEM_freeN(nu->bezt);
2701                                 nu->bezt= beztnew;
2702                                 nu->pntsu+= amount;
2703
2704                                 calchandlesNurb(nu);
2705                         }
2706                 } /* End of 'if(nu->type == CU_BEZIER)' */
2707                 else if (nu->pntsv==1) {
2708                 /* 
2709                    All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves 
2710                    are handled together with the regular NURB plane division, as it 
2711                    should be. I split it off just now, let's see if it is
2712                    stable... nzc 30-5-'00
2713                  */
2714                         /* count */
2715                         if(nu->flagu & CU_NURB_CYCLIC) {
2716                                 a= nu->pntsu;
2717                                 bp= nu->bp;
2718                                 prevbp= bp+(a-1);
2719                         }
2720                         else {
2721                                 a= nu->pntsu-1;
2722                                 prevbp= nu->bp;
2723                                 bp= prevbp+1;
2724                         }
2725                         while(a--) {
2726                                 if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount+=number_cuts;
2727                                 prevbp= bp;
2728                                 bp++;
2729                         }
2730
2731                         if(amount) {
2732                                 /* insert */
2733                                 bpnew =
2734                                         (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
2735                                 bpn= bpnew;
2736
2737                                 if(nu->flagu & CU_NURB_CYCLIC) {
2738                                         a= nu->pntsu;
2739                                         bp= nu->bp;
2740                                         prevbp= bp+(a-1);
2741                                 }
2742                                 else {
2743                                         a= nu->pntsu-1;
2744                                         prevbp= nu->bp;
2745                                         bp= prevbp+1;
2746                                 }
2747                                 while(a--) {
2748                                         memcpy(bpn, prevbp, sizeof(BPoint));
2749                                         bpn++;
2750
2751                                         if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) {
2752                                  // printf("*** subdivideNurb: insert 'linear' point\n");
2753                                                 for (i = 0; i < number_cuts; i++) {
2754                                                         factor = (float)(i + 1) / (number_cuts + 1);
2755
2756                                                         memcpy(bpn, bp, sizeof(BPoint));
2757                                                         interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
2758                                                         bpn++;
2759                                                 }
2760
2761                                         }
2762                                         prevbp= bp;
2763                                         bp++;
2764                                 }
2765                                 if((nu->flagu & CU_NURB_CYCLIC)==0) memcpy(bpn, prevbp, sizeof(BPoint));        /* last point */
2766
2767                                 MEM_freeN(nu->bp);
2768                                 nu->bp= bpnew;
2769                                 nu->pntsu+= amount;
2770
2771                                 if(nu->type & CU_NURBS) {
2772                                         makeknots(nu, 1);
2773                                 }
2774                         }
2775                 } /* End of 'else if(nu->pntsv==1)' */
2776                 else if(nu->type == CU_NURBS) {
2777                 /* This is a very strange test ... */
2778                 /** 
2779                    Subdivide NURB surfaces - nzc 30-5-'00 -
2780            
2781                          Subdivision of a NURB curve can be effected by adding a 
2782                    control point (insertion of a knot), or by raising the
2783                    degree of the functions used to build the NURB. The
2784                    expression 
2785
2786                            degree = #knots - #controlpoints + 1 (J Walter piece)
2787                            degree = #knots - #controlpoints     (Blender
2788                                                                                                           implementation)
2789                                  ( this is confusing.... what is true? Another concern
2790                                  is that the JW piece allows the curve to become
2791                                  explicitly 1st order derivative discontinuous, while
2792                                  this is not what we want here... )
2793
2794                    is an invariant for a single NURB curve. Raising the degree
2795                    of the NURB is done elsewhere; the degree is assumed
2796                    constant during this opration. Degree is a property shared
2797                    by all controlpoints in a curve (even though it is stored
2798                    per control point - this can be misleading).
2799                          Adding a knot is done by searching for the place in the
2800                    knot vector where a certain knot value must be inserted, or
2801                    by picking an appropriate knot value between two existing
2802                    ones. The number of controlpoints that is influenced by the
2803                    insertion depends on the order of the curve. A certain
2804                    minimum number of knots is needed to form high-order
2805                    curves, as can be seen from the equation above. In Blender,
2806                    currently NURBs may be up to 6th order, so we modify at
2807                    most 6 points. One point is added. For an n-degree curve,
2808                    n points are discarded, and n+1 points inserted
2809                    (so effectively, n points are modified).  (that holds for
2810                    the JW piece, but it seems not for our NURBs)
2811                           In practice, the knot spacing is copied, but the tail
2812                    (the points following the insertion point) need to be
2813                    offset to keep the knot series ascending. The knot series
2814                    is always a series of monotonically ascending integers in
2815                    Blender. When not enough control points are available to
2816                    fit the order, duplicates of the endpoints are added as
2817                    needed. 
2818                 */
2819                         /* selection-arrays */
2820                         usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
2821                         vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
2822                         sel= 0;
2823
2824                  /* Count the number of selected points. */
2825                         bp= nu->bp;
2826                         for(a=0; a<nu->pntsv; a++) {
2827                                 for(b=0; b<nu->pntsu; b++) {
2828                                         if(bp->f1 & SELECT) {
2829                                                 usel[b]++;
2830                                                 vsel[a]++;
2831                                                 sel++;
2832                                         }
2833                                         bp++;
2834                                 }
2835                         }
2836                         if( sel == (nu->pntsu*nu->pntsv) ) {    /* subdivide entire nurb */
2837                    /* Global subdivision is a special case of partial
2838                           subdivision. Strange it is considered separately... */
2839
2840                                 /* count of nodes (after subdivision) along U axis */
2841      &nb