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