f2e05da79955f88906cb874faf307247e3bb26bb
[blender-staging.git] / source / blender / editors / curve / editcurve.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <string.h>
32
33 #ifndef WIN32
34 #include <unistd.h>
35 #else
36 #include <io.h>
37 #endif
38 #include <stdlib.h>
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_math.h"
43 #include "BLI_dynstr.h"
44 #include "BLI_rand.h"
45 #include "BLI_ghash.h"
46
47 #include "DNA_key_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_scene_types.h"
50
51 #include "BKE_context.h"
52 #include "BKE_curve.h"
53 #include "BKE_depsgraph.h"
54 #include "BKE_fcurve.h"
55 #include "BKE_global.h"
56 #include "BKE_key.h"
57 #include "BKE_library.h"
58 #include "BKE_main.h"
59 #include "BKE_object.h"
60 #include "BKE_report.h"
61 #include "BKE_utildefines.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "ED_keyframes_edit.h"
67 #include "ED_object.h"
68 #include "ED_screen.h"
69 #include "ED_transform.h"
70 #include "ED_types.h"
71 #include "ED_util.h"
72 #include "ED_view3d.h"
73 #include "ED_curve.h"
74
75 #include "UI_interface.h"
76
77 #include "RNA_access.h"
78 #include "RNA_define.h"
79
80 /* Undo stuff */
81 typedef struct {
82         ListBase nubase;
83         void *lastsel;
84         GHash *undoIndex;
85 } UndoCurve;
86
87 /* Definitions needed for shape keys */
88 typedef struct {
89         void *origNode;
90         int index;
91 } NodeKeyIndex;
92
93 void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus);
94 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus);
95
96 /* still need to eradicate a few :( */
97 #define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
98
99 float nurbcircle[8][2]= {
100         {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0,  1.0},
101         {0.0,  1.0}, { 1.0,  1.0}, { 1.0, 0.0}, { 1.0, -1.0}
102 };
103
104 ListBase *curve_get_editcurve(Object *ob)
105 {
106         if(ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
107                 Curve *cu= ob->data;
108                 return &cu->editnurb->nurbs;
109         }
110         return NULL;
111 }
112
113 /* this replaces the active flag used in uv/face mode */
114 void set_actNurb(Object *obedit, Nurb *nu)
115 {
116         Curve *cu= obedit->data;
117         
118         if(nu==NULL)
119                 cu->actnu = -1;
120         else {
121                 ListBase *nurbs= ED_curve_editnurbs(cu);
122                 cu->actnu = BLI_findindex(nurbs, nu);
123         }
124 }
125
126 Nurb *get_actNurb(Object *obedit)
127 {
128         Curve *cu= obedit->data;
129         ListBase *nurbs= ED_curve_editnurbs(cu);
130
131         return BLI_findlink(nurbs, cu->actnu);
132 }
133
134 /* ******************* SELECTION FUNCTIONS ********************* */
135
136 #define HIDDEN                  1
137 #define VISIBLE                 0
138
139 #define FIRST                   1
140 #define LAST                    0
141
142
143 /* returns 1 in case (de)selection was successful */
144 static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden)
145 {       
146         if(bezt) {
147                 if((bezt->hide==0) || (hidden==1)) {
148                         if(selstatus==1) { /* selects */                        
149                                 bezt->f1 |= flag;
150                                 bezt->f2 |= flag;
151                                 bezt->f3 |= flag;
152                                 return 1;                       
153                         }
154                         else { /* deselects */  
155                                 bezt->f1 &= ~flag; 
156                                 bezt->f2 &= ~flag; 
157                                 bezt->f3 &= ~flag; 
158                                 return 1;
159                         }
160                 }
161         }
162         
163         return 0;
164 }
165
166 /* returns 1 in case (de)selection was successful */
167 static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden) 
168 {       
169         if(bp) {
170                 if((bp->hide==0) || (hidden==1)) {
171                         if(selstatus==1) {
172                                 bp->f1 |= flag;
173                                 return 1;
174                         }
175                         else {
176                                 bp->f1 &= ~flag;
177                                 return 1;
178                         }
179                 }
180         }
181
182         return 0;
183 }
184
185 static short swap_selection_beztriple(BezTriple *bezt)
186 {
187         if(bezt->f2 & SELECT)
188                 return select_beztriple(bezt, DESELECT, 1, VISIBLE);
189         else
190                 return select_beztriple(bezt, SELECT, 1, VISIBLE);
191 }
192
193 static short swap_selection_bpoint(BPoint *bp)
194 {
195         if(bp->f1 & SELECT)
196                 return select_bpoint(bp, DESELECT, 1, VISIBLE);
197         else
198                 return select_bpoint(bp, SELECT, 1, VISIBLE);
199 }
200
201 int isNurbsel(Nurb *nu)
202 {
203         BezTriple *bezt;
204         BPoint *bp;
205         int a;
206
207         if(nu->type == CU_BEZIER) {
208                 bezt= nu->bezt;
209                 a= nu->pntsu;
210                 while(a--) {
211                         if( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) return 1;
212                         bezt++;
213                 }
214         }
215         else {
216                 bp= nu->bp;
217                 a= nu->pntsu*nu->pntsv;
218                 while(a--) {
219                         if( (bp->f1 & SELECT) ) return 1;
220                         bp++;
221                 }
222         }
223         return 0;
224 }
225
226 int isNurbsel_count(Curve *cu, Nurb *nu)
227 {
228         BezTriple *bezt;
229         BPoint *bp;
230         int a, sel=0;
231
232         if(nu->type == CU_BEZIER) {
233                 bezt= nu->bezt;
234                 a= nu->pntsu;
235                 while(a--) {
236                         if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) sel++;
237                         bezt++;
238                 }
239         }
240         else {
241                 bp= nu->bp;
242                 a= nu->pntsu*nu->pntsv;
243                 while(a--) {
244                         if( (bp->f1 & SELECT) ) sel++;
245                         bp++;
246                 }
247         }
248         return sel;
249 }
250
251 /* ******************* PRINTS ********************* */
252
253 void printknots(Object *obedit)
254 {
255         ListBase *editnurb= curve_get_editcurve(obedit);
256         Nurb *nu;
257         int a, num;
258
259         for(nu= editnurb->first; nu; nu= nu->next) {
260                 if(isNurbsel(nu) &&  nu->type == CU_NURBS) {
261                         if(nu->knotsu) {
262                                 num= KNOTSU(nu);
263                                 for(a=0;a<num;a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
264                         }
265                         if(nu->knotsv) {
266                                 num= KNOTSV(nu);
267                                 for(a=0;a<num;a++) printf("knotv %d: %f\n", a, nu->knotsv[a]);
268                         }
269                 }
270         }
271 }
272
273 /* ********************* Shape keys *************** */
274
275 static NodeKeyIndex *init_nodeKeyIndex(void *node, int index)
276 {
277         NodeKeyIndex *nodeIndex = MEM_callocN(sizeof(NodeKeyIndex), "init_nodeKeyIndex");
278
279         nodeIndex->origNode= node;
280         nodeIndex->index= index;
281
282         return nodeIndex;
283 }
284
285 static void free_nodeKeyIndex(NodeKeyIndex *pointIndex)
286 {
287         MEM_freeN(pointIndex);
288 }
289
290 static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
291 {
292         Nurb *nu= editnurb->nurbs.first;
293         Nurb *orignu= origBase->first;
294         GHash *gh;
295         BezTriple *bezt, *origbezt;
296         BPoint *bp, *origbp;
297         int a, keyindex= 0;
298
299         gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "editNurb keyIndex");
300
301         while (orignu) {
302                 if (orignu->bezt) {
303                         a= orignu->pntsu;
304                         bezt= nu->bezt;
305                         origbezt= orignu->bezt;
306                         while (a--) {
307                                 BLI_ghash_insert(gh, bezt, init_nodeKeyIndex(origbezt, keyindex));
308                                 keyindex+= 12;
309                                 bezt++;
310                                 origbezt++;
311                         }
312                 } else {
313                         a= orignu->pntsu * orignu->pntsv;
314                         bp= nu->bp;
315                         origbp= orignu->bp;
316                         while (a--) {
317                                 BLI_ghash_insert(gh, bp, init_nodeKeyIndex(origbp, keyindex));
318                                 keyindex+= 4;
319                                 bp++;
320                                 origbp++;
321                         }
322                 }
323
324                 nu= nu->next;
325                 orignu= orignu->next;
326         }
327
328         editnurb->keyindex= gh;
329 }
330
331 static void free_editNurb_keyIndex(EditNurb *editnurb)
332 {
333         if (!editnurb->keyindex) {
334                 return;
335         }
336         BLI_ghash_free(editnurb->keyindex, NULL, (GHashValFreeFP)free_nodeKeyIndex);
337 }
338
339 static NodeKeyIndex *getNodeKeyIndex(EditNurb *editnurb, void *node)
340 {
341         return BLI_ghash_lookup(editnurb->keyindex, node);
342 }
343
344 static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, void *node)
345 {
346         NodeKeyIndex *index= getNodeKeyIndex(editnurb, node);
347
348         if (!index) {
349                 return NULL;
350         }
351
352         return (BezTriple*)index->origNode;
353 }
354
355 static BPoint *getKeyIndexOrig_bp(EditNurb *editnurb, void *node)
356 {
357         NodeKeyIndex *index= getNodeKeyIndex(editnurb, node);
358
359         if (!index) {
360                 return NULL;
361         }
362
363         return (BPoint*)index->origNode;
364 }
365
366 static int getKeyIndexOrig_index(EditNurb *editnurb, void *node)
367 {
368         NodeKeyIndex *index= getNodeKeyIndex(editnurb, node);
369
370         if (!index) {
371                 return -1;
372         }
373
374         return index->index;
375 }
376
377 static void keyIndex_delNode(EditNurb *editnurb, void *node)
378 {
379         if (!editnurb->keyindex) {
380                 return;
381         }
382
383         BLI_ghash_remove(editnurb->keyindex, node, NULL, (GHashValFreeFP)free_nodeKeyIndex);
384 }
385
386 static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
387 {
388         keyIndex_delNode(editnurb, bezt);
389 }
390
391 static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp)
392 {
393         keyIndex_delNode(editnurb, bp);
394 }
395
396 static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
397 {
398         int a;
399
400         if (!editnurb->keyindex) {
401                 return;
402         }
403
404         if (nu->bezt) {
405                 BezTriple *bezt= nu->bezt;
406                 a= nu->pntsu;
407
408                 while (a--) {
409                         BLI_ghash_remove(editnurb->keyindex, bezt, NULL, (GHashValFreeFP)free_nodeKeyIndex);
410                         ++bezt;
411                 }
412         } else {
413                 BPoint *bp= nu->bp;
414                 a= nu->pntsu * nu->pntsv;
415
416                 while (a--) {
417                         BLI_ghash_remove(editnurb->keyindex, bp, NULL, (GHashValFreeFP)free_nodeKeyIndex);
418                         ++bp;
419                 }
420         }
421 }
422
423 static void keyIndex_delNurbList(EditNurb *editnurb, ListBase *nubase)
424 {
425         Nurb *nu= nubase->first;
426
427         while (nu) {
428                 keyIndex_delNurb(editnurb, nu);
429
430                 nu= nu->next;
431         }
432 }
433
434 static void keyIndex_updateNode(EditNurb *editnurb, char *node,
435         char *newnode, int count, int size, int search)
436 {
437         int i;
438         NodeKeyIndex *index;
439
440         if (editnurb->keyindex == NULL) {
441                 /* No shape keys - updating not needed */
442                 return;
443         }
444
445         for (i = 0; i < count; i++) {
446                 for (;;) {
447                         index= getNodeKeyIndex(editnurb, node);
448                         if (!search || index) {
449                                 break;
450                         }
451                         node += size;
452                 }
453
454                 BLI_ghash_remove(editnurb->keyindex, node, NULL, NULL);
455
456                 if (index) {
457                         BLI_ghash_insert(editnurb->keyindex, newnode, index);
458                 }
459
460                 newnode += size;
461                 node += size;
462         }
463 }
464
465 static void keyIndex_updateBezt(EditNurb *editnurb, BezTriple *bezt,
466         BezTriple *newbezt, int count, int search)
467 {
468         keyIndex_updateNode(editnurb, (char*)bezt, (char*)newbezt, count, sizeof(BezTriple), search);
469 }
470
471 static void keyIndex_updateBP(EditNurb *editnurb, BPoint *bp,
472         BPoint *newbp, int count, int search)
473 {
474         keyIndex_updateNode(editnurb, (char*)bp, (char*)newbp, count, sizeof(BPoint), search);
475 }
476
477 static void keyIndex_updateNurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
478 {
479         if (nu->bezt) {
480                 keyIndex_updateBezt(editnurb, nu->bezt, newnu->bezt, newnu->pntsu, 0);
481         } else {
482                 keyIndex_updateBP(editnurb, nu->bp, newnu->bp, newnu->pntsu * newnu->pntsv, 0);
483         }
484 }
485
486 static void keyIndex_swap(EditNurb *editnurb, void *a, void *b)
487 {
488         NodeKeyIndex *index1= getNodeKeyIndex(editnurb, a);
489         NodeKeyIndex *index2= getNodeKeyIndex(editnurb, b);
490
491         BLI_ghash_remove(editnurb->keyindex, a, NULL, NULL);
492         BLI_ghash_remove(editnurb->keyindex, b, NULL, NULL);
493
494         BLI_ghash_insert(editnurb->keyindex, a, index2);
495         BLI_ghash_insert(editnurb->keyindex, b, index1);
496 }
497
498 static void keyIndex_switchDirection(EditNurb *editnurb, Nurb *nu)
499 {
500         int a;
501
502         if (nu->bezt) {
503                 BezTriple *bezt1, *bezt2;
504
505                 a= nu->pntsu;
506
507                 bezt1= nu->bezt;
508                 bezt2= bezt1+(a-1);
509
510                 if (a & 1) ++a;
511
512                 a/=2;
513
514                 while (a--) {
515                         if (bezt1 != bezt2) {
516                                 keyIndex_swap(editnurb, bezt1, bezt2);
517                         }
518
519                         bezt1++;
520                         bezt2--;
521                 }
522         } else {
523                 BPoint *bp1, *bp2;
524
525                 if (nu->pntsv == 1) {
526                         a= nu->pntsu;
527                         bp1= nu->bp;
528                         bp2= bp1+(a-1);
529                         a/= 2;
530                         while(bp1!=bp2 && a>0) {
531                                 if (bp1 != bp2) {
532                                         keyIndex_swap(editnurb, bp1, bp2);
533                                 }
534
535                                 a--;
536                                 bp1++;
537                                 bp2--;
538                         }
539                 } else {
540                         int b;
541
542                         for(b=0; b<nu->pntsv; b++) {
543
544                                 bp1= nu->bp+b*nu->pntsu;
545                                 a= nu->pntsu;
546                                 bp2= bp1+(a-1);
547                                 a/= 2;
548
549                                 while(bp1!=bp2 && a>0) {
550                                         if (bp1 != bp2) {
551                                                 keyIndex_swap(editnurb, bp1, bp2);
552                                         }
553
554                                         a--;
555                                         bp1++;
556                                         bp2--;
557                                 }
558                         }
559
560                 }
561         }
562 }
563
564 static void switch_keys_direction(Curve *cu, Nurb *actnu)
565 {
566         KeyBlock *currkey;
567         ListBase *nubase= &cu->editnurb->nurbs;
568         Nurb *nu;
569         float *fp;
570         int a;
571
572         currkey = cu->key->block.first;
573         while(currkey) {
574                 fp= currkey->data;
575
576                 nu= nubase->first;
577                 while (nu) {
578                         if (nu->bezt) {
579                                 a= nu->pntsu;
580                                 if (nu == actnu) {
581                                         while (a--) {
582                                                 swap_v3_v3(fp, fp + 6);
583                                                 *(fp+9) = -*(fp+9);
584                                                 fp += 12;
585                                         }
586                                 } else fp += a * 12;
587                         } else {
588                                 a= nu->pntsu * nu->pntsv;
589                                 if (nu == actnu) {
590                                         while (a--) {
591                                                 *(fp+3) = -*(fp+3);
592                                                 fp += 4;
593                                         }
594                                 } else fp += a * 4;
595                         }
596
597                         nu= nu->next;
598                 }
599
600                 currkey= currkey->next;
601         }
602 }
603
604 static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu)
605 {
606         EditNurb *editnurb= cu->editnurb;
607
608         if (!editnurb->keyindex) {
609                 /* no shape keys - nothing to do */
610                 return;
611         }
612
613         keyIndex_switchDirection(editnurb, nu);
614         switch_keys_direction(cu, nu);
615 }
616
617 static GHash *dupli_keyIndexHash(GHash *keyindex)
618 {
619         GHash *gh;
620         GHashIterator *hashIter;
621
622         gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "dupli_keyIndex gh");
623
624         for(hashIter = BLI_ghashIterator_new(keyindex);
625                                    !BLI_ghashIterator_isDone(hashIter);
626                                    BLI_ghashIterator_step(hashIter)) {
627                 void *node = BLI_ghashIterator_getKey(hashIter);
628                 NodeKeyIndex *index = BLI_ghashIterator_getValue(hashIter);
629                 NodeKeyIndex *newIndex = MEM_callocN(sizeof(NodeKeyIndex), "dupli_keyIndexHash index");
630
631                 memcpy(newIndex, index, sizeof(NodeKeyIndex));
632
633                 BLI_ghash_insert(gh, node, newIndex);
634         }
635
636         BLI_ghashIterator_free(hashIter);
637
638         return gh;
639 }
640
641 static void key_to_bezt(float *key, BezTriple *basebezt, BezTriple *bezt)
642 {
643         memcpy(bezt, basebezt, sizeof(BezTriple));
644         memcpy(bezt->vec, key, sizeof(float) * 9);
645         bezt->alfa= key[9];
646 }
647
648 static void bezt_to_key(BezTriple *bezt, float *key)
649 {
650          memcpy(key, bezt->vec, sizeof(float) * 9);
651          key[9] = bezt->alfa;
652 }
653
654 static void calc_keyHandles(ListBase *nurb, float *key)
655 {
656         Nurb *nu;
657         int a;
658         float *fp= key;
659         BezTriple *bezt;
660
661         nu= nurb->first;
662         while (nu) {
663                 if (nu->bezt) {
664                         BezTriple *prevp, *nextp;
665                         BezTriple cur, prev, next;
666                         float *startfp, *prevfp, *nextfp;
667
668                         bezt= nu->bezt;
669                         a= nu->pntsu;
670                         startfp= fp;
671
672                         if(nu->flagu & CU_NURB_CYCLIC) {
673                                 prevp= bezt+(a-1);
674                                 prevfp= fp+(12 * (a-1));
675                         } else {
676                                 prevp= NULL;
677                                 prevfp= NULL;
678                         }
679
680                         nextp= bezt + 1;
681                         nextfp= fp + 12;
682
683                         while (a--) {
684                                 key_to_bezt(fp, bezt, &cur);
685
686                                 if (nextp) key_to_bezt(nextfp, nextp, &next);
687                                 if (prevp) key_to_bezt(prevfp, prevp, &prev);
688
689                                 calchandleNurb(&cur, prevp ? &prev : NULL, nextp ? &next : NULL, 0);
690                                 bezt_to_key(&cur, fp);
691
692                                 prevp= bezt;
693                                 prevfp= fp;
694                                 if(a==1) {
695                                         if(nu->flagu & CU_NURB_CYCLIC) {
696                                                 nextp= nu->bezt;
697                                                 nextfp= startfp;
698                                         } else {
699                                                 nextp= NULL;
700                                                 nextfp= NULL;
701                                         }
702                                 }
703                                 else {
704                                         ++nextp;
705                                         nextfp += 12;;
706                                 }
707
708                                 ++bezt;
709                                 fp += 12;
710                         }
711                 } else {
712                         a= nu->pntsu * nu->pntsv;
713                         fp += a * 4;
714                 }
715
716                 nu= nu->next;
717         }
718 }
719
720 static void calc_shapeKeys(Object *obedit)
721 {
722         Curve *cu= (Curve*)obedit->data;
723
724         /* are there keys? */
725         if(cu->key) {
726                 int a, i, j;
727                 EditNurb *editnurb= cu->editnurb;
728                 KeyBlock *currkey;
729                 KeyBlock *actkey= ob_get_keyblock(obedit);
730                 BezTriple *bezt, *oldbezt;
731                 BPoint *bp, *oldbp;
732                 Nurb *nu;
733                 int totvert= count_curveverts(&editnurb->nurbs);
734
735                 float (*ofs)[3] = NULL;
736                 float *oldkey, *newkey, *fp, *ofp;
737
738                 /* editing the base key should update others */
739                 if(cu->key->type==KEY_RELATIVE) {
740                         int act_is_basis = 0;
741                         /* find if this key is a basis for any others */
742                         for(currkey = cu->key->block.first; currkey; currkey= currkey->next) {
743                                 if(obedit->shapenr-1 == currkey->relative) {
744                                         act_is_basis = 1;
745                                         break;
746                                 }
747                         }
748
749                         if(act_is_basis) { /* active key is a base */
750                                 int j;
751                                 int totvec= 0;
752
753                                 /* Calculate needed memory to store offset */
754                                 nu= editnurb->nurbs.first;
755                                 while(nu) {
756                                         if (nu->bezt) {
757                                                 /* Three vects to store handles and one for alfa */
758                                                 totvec+= nu->pntsu * 4;
759                                         } else {
760                                                 totvec+= 2 * nu->pntsu * nu->pntsv;
761                                         }
762
763                                         nu= nu->next;
764                                 }
765
766                                 ofs= MEM_callocN(sizeof(float) * 3 * totvec,  "currkey->data");
767                                 nu= editnurb->nurbs.first;
768                                 i= 0;
769                                 while(nu) {
770                                         if(nu->bezt) {
771                                                 bezt= nu->bezt;
772                                                 a= nu->pntsu;
773                                                 while(a--) {
774                                                         oldbezt= getKeyIndexOrig_bezt(editnurb, bezt);
775
776                                                         if (oldbezt) {
777                                                                 for (j= 0; j < 3; ++j) {
778                                                                         VECSUB(ofs[i], bezt->vec[j], oldbezt->vec[j]);
779                                                                         i++;
780                                                                         fp+= 3;
781                                                                 }
782                                                                 ofs[i++][0]= bezt->alfa - oldbezt->alfa;
783                                                         } else {
784                                                                 i += 4;
785                                                         }
786                                                         bezt++;
787                                                 }
788                                         }
789                                         else {
790                                                 bp= nu->bp;
791                                                 a= nu->pntsu*nu->pntsv;
792                                                 while(a--) {
793                                                         oldbp= getKeyIndexOrig_bp(editnurb, bp);
794                                                         if (oldbp) {
795                                                                 VECSUB(ofs[i], bp->vec, oldbp->vec);
796                                                                 ofs[i+1][0]= bp->alfa - oldbp->alfa;
797                                                         }
798                                                         i += 2;
799                                                         ++bp;
800                                                         fp += 4;
801                                                 }
802                                         }
803
804                                         nu= nu->next;
805                                 }
806                         }
807                 }
808
809                 currkey = cu->key->block.first;
810                 while(currkey) {
811                         int apply_offset = (ofs && (currkey != actkey) && (obedit->shapenr-1 == currkey->relative));
812
813                         fp= newkey= MEM_callocN(cu->key->elemsize * totvert,  "currkey->data");
814                         ofp= oldkey = currkey->data;
815
816                         nu= editnurb->nurbs.first;
817                         i = 0;
818                         while(nu) {
819                                 if(currkey == actkey) {
820                                         int restore= actkey != cu->key->refkey;
821
822                                         if(nu->bezt) {
823                                                 bezt= nu->bezt;
824                                                 a= nu->pntsu;
825                                                 while(a--) {
826                                                         oldbezt= getKeyIndexOrig_bezt(editnurb, bezt);
827
828                                                         for (j= 0; j < 3; ++j, ++i) {
829                                                                 VECCOPY(fp, bezt->vec[j]);
830
831                                                                 if (restore && oldbezt) {
832                                                                         VECCOPY(bezt->vec[j], oldbezt->vec[j]);
833                                                                 }
834
835                                                                 fp+= 3;
836                                                         }
837                                                         fp[0]= bezt->alfa;
838
839                                                         if(restore && oldbezt) {
840                                                                 bezt->alfa= oldbezt->alfa;
841                                                         }
842
843                                                         fp+= 3; ++i;/* alphas */
844                                                         ++bezt;
845                                                 }
846                                         }
847                                         else {
848                                                 bp= nu->bp;
849                                                 a= nu->pntsu*nu->pntsv;
850                                                 while(a--) {
851                                                         oldbp= getKeyIndexOrig_bp(editnurb, bp);
852
853                                                         VECCOPY(fp, bp->vec);
854
855                                                         fp[3]= bp->alfa;
856
857                                                         if(restore && oldbp) {
858                                                                 VECCOPY(bp->vec, oldbp->vec);
859                                                                 bp->alfa= oldbp->alfa;
860                                                         }
861
862                                                         fp+= 4;
863                                                         ++bp;
864                                                         i+=2;
865                                                 }
866                                         }
867                                 }
868                                 else {
869                                         int index;
870                                         float *curofp;
871
872                                         if(oldkey) {
873                                                 if(nu->bezt) {
874                                                         bezt= nu->bezt;
875                                                         a= nu->pntsu;
876
877                                                         while(a--) {
878                                                                 index= getKeyIndexOrig_index(editnurb, bezt);
879                                                                 if (index >= 0) {
880                                                                         curofp= ofp + index;
881
882                                                                         for (j= 0; j < 3; ++j, ++i) {
883                                                                                 VECCOPY(fp, curofp);
884
885                                                                                 if(apply_offset) {
886                                                                                         VECADD(fp, fp, ofs[i]);
887                                                                                 }
888
889                                                                                 fp+= 3; curofp+= 3;
890                                                                         }
891                                                                         fp[0]= curofp[0];
892
893                                                                         if(apply_offset) {
894                                                                                 /* apply alfa offsets */
895                                                                                 VECADD(fp, fp, ofs[i]);
896                                                                                 ++i;
897                                                                         }
898
899                                                                         fp+= 3; curofp+= 3;     /* alphas */
900                                                                 } else {
901                                                                         for (j= 0; j < 3; ++j, ++i) {
902                                                                                 VECCOPY(fp, bezt->vec[j]);
903                                                                                 fp+= 3;
904                                                                         }
905                                                                         fp[0]= bezt->alfa;
906
907                                                                         fp+= 3; /* alphas */
908                                                                 }
909                                                                 ++bezt;
910                                                         }
911                                                 }
912                                                 else {
913                                                         bp= nu->bp;
914                                                         a= nu->pntsu*nu->pntsv;
915                                                         while(a--) {
916                                                                 index= getKeyIndexOrig_index(editnurb, bp);
917
918                                                                 if (index >= 0) {
919                                                                         curofp= ofp + index;
920                                                                         VECCOPY(fp, curofp);
921                                                                         fp[3]= curofp[3];
922
923                                                                         if(apply_offset) {
924                                                                                 VECADD(fp, fp, ofs[i]);
925                                                                                 fp[3]+=ofs[i+1][0];
926                                                                         }
927                                                                 } else {
928                                                                         VECCOPY(fp, bp->vec);
929                                                                         fp[3]= bp->alfa;
930                                                                 }
931
932                                                                 fp+= 4;
933                                                                 ++bp;
934                                                                 i+=2;
935                                                         }
936                                                 }
937                                         }
938                                 }
939
940                                 nu= nu->next;
941                         }
942
943                         if (apply_offset) {
944                                 /* handles could become malicious after offsets applying */
945                                 calc_keyHandles(&editnurb->nurbs, newkey);
946                         }
947
948                         currkey->totelem= totvert;
949                         if(currkey->data) MEM_freeN(currkey->data);
950                         currkey->data = newkey;
951
952                         currkey= currkey->next;
953                 }
954
955                 if(ofs) MEM_freeN(ofs);
956         }
957 }
958
959 /* ********************* LOAD and MAKE *************** */
960
961 /* load editNurb in object */
962 void load_editNurb(Object *obedit)
963 {
964         ListBase *editnurb= curve_get_editcurve(obedit);
965
966         if(obedit==NULL) return;
967
968         set_actNurb(obedit, NULL);
969
970         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
971                 Curve *cu= obedit->data;
972                 Nurb *nu, *newnu;
973                 ListBase newnurb= {NULL, NULL}, oldnurb= cu->nurb;
974
975                 for(nu= editnurb->first; nu; nu= nu->next) {
976                         newnu= duplicateNurb(nu);
977                         BLI_addtail(&newnurb, newnu);
978
979                         if(nu->type == CU_NURBS) {
980                                 clamp_nurb_order_u(nu);
981                         }
982                 }
983
984                 cu->nurb= newnurb;
985
986                 calc_shapeKeys(obedit);
987
988                 freeNurblist(&oldnurb);
989         }
990
991         set_actNurb(obedit, NULL);
992 }
993
994 /* make copy in cu->editnurb */
995 void make_editNurb(Object *obedit)
996 {
997         Curve *cu= (Curve*)obedit->data;
998         EditNurb *editnurb= cu->editnurb;
999         Nurb *nu, *newnu, *nu_act= NULL;
1000         KeyBlock *actkey;
1001
1002         if(obedit==NULL) return;
1003
1004         set_actNurb(obedit, NULL);
1005
1006         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1007                 actkey = ob_get_keyblock(obedit);
1008                 if(actkey) {
1009                         // XXX strcpy(G.editModeTitleExtra, "(Key) ");
1010                         undo_editmode_clear();
1011                         key_to_curve(actkey, cu, &cu->nurb);
1012                 }
1013
1014                 if(editnurb) {
1015                         freeNurblist(&editnurb->nurbs);
1016                         free_editNurb_keyIndex(editnurb);
1017                         editnurb->keyindex= NULL;
1018                 } else {
1019                         editnurb= MEM_callocN(sizeof(EditNurb), "editnurb");
1020                         cu->editnurb= editnurb;
1021                 }
1022
1023                 nu= cu->nurb.first;
1024                 cu->lastsel= NULL;   /* for select row */
1025
1026                 while(nu) {
1027                         newnu= duplicateNurb(nu);
1028                         test2DNurb(newnu);      // after join, or any other creation of curve
1029                         BLI_addtail(&editnurb->nurbs, newnu);
1030
1031                         if (nu_act == NULL && isNurbsel(nu)) {
1032                                 nu_act= newnu;
1033                                 set_actNurb(obedit, newnu);
1034                         }
1035
1036                         nu= nu->next;
1037                 }
1038
1039                 if(actkey) {
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)