Merging revisions 14946-15020 of https://svn.blender.org/svnroot/bf-blender/trunk...
[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&1)) {
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                                         if(nu->resolv<3) nu->resolv++;
832                                         makeknots(nu, 2, nu->flagv>>1);
833                                 }
834                                 else if(v==0 || v== nu->pntsu-1) {          /* collumn in v-direction selected */
835                                         ok= 1;
836                                         bpn = newbp =
837                                                 (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
838                                         bp= nu->bp;
839
840                                         for(a=0; a<nu->pntsv; a++) {
841                                                 if(v==0) {
842                                                         *bpn= *bp;
843                                                         bpn->f1 |= flag;
844                                                         bpn++;
845                                                 }
846                                                 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
847                                                 bp+= nu->pntsu;
848                                                 bpn+= nu->pntsu;
849                                                 if(v== nu->pntsu-1) {
850                                                         *bpn= *(bp-1);
851                                                         bpn->f1 |= flag;
852                                                         bpn++;
853                                                 }
854                                         }
855
856                                         MEM_freeN(nu->bp);
857                                         nu->bp= newbp;
858                                         nu->pntsu++;
859                                         if(nu->resolu<3) nu->resolu++;
860                                         makeknots(nu, 1, nu->flagu>>1);
861                                 }
862                         }
863                 }
864                 nu= nu->next;
865         }
866
867         return ok;
868 }
869
870 void adduplicateflagNurb(short flag)
871 {
872         Nurb *nu, *newnu;
873         BezTriple *bezt, *bezt1;
874         BPoint *bp, *bp1;
875         int a, b, starta, enda, newu, newv;
876         char *usel;
877
878         nu= editNurb.last;
879         while(nu) {
880                 if( (nu->type & 7)==CU_BEZIER) {
881                         bezt= nu->bezt;
882                         for(a=0; a<nu->pntsu; a++) {
883                                 enda= -1;
884                                 starta= a;
885                                 while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
886                                         select_beztriple(bezt, DESELECT, flag, HIDDEN);
887                                         enda=a;
888                                         if(a>=nu->pntsu-1) break;
889                                         a++;
890                                         bezt++;
891                                 }
892                                 if(enda>=starta) {
893                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");  
894                                         memcpy(newnu, nu, sizeof(Nurb));
895                                         BLI_addtail(&editNurb, newnu);
896                                         set_actNurb(newnu);
897                                         newnu->pntsu= enda-starta+1;
898                                         newnu->bezt=
899                                                 (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");  
900                                         memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
901
902                                         b= newnu->pntsu;
903                                         bezt1= newnu->bezt;
904                                         while(b--) {
905                                                 select_beztriple(bezt1, SELECT, flag, HIDDEN);
906                                                 bezt1++;
907                                         }
908
909                                         if(nu->flagu & CU_CYCLIC) {
910                                                 if(starta!=0 || enda!=nu->pntsu-1) {
911                                                         newnu->flagu &= ~CU_CYCLIC;
912                                                 }
913                                         }
914                                 }
915                                 bezt++;
916                         }
917                 }
918                 else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
919                         bp= nu->bp;
920                         for(a=0; a<nu->pntsu; a++) {
921                                 enda= -1;
922                                 starta= a;
923                                 while(bp->f1 & flag) {
924                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
925                                         enda= a;
926                                         if(a>=nu->pntsu-1) break;
927                                         a++;
928                                         bp++;
929                                 }
930                                 if(enda>=starta) {
931                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");  
932                                         memcpy(newnu, nu, sizeof(Nurb));
933                                         set_actNurb(newnu);
934                                         BLI_addtail(&editNurb, newnu);
935                                         newnu->pntsu= enda-starta+1;
936                                         newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
937                                         memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
938
939                                         b= newnu->pntsu;
940                                         bp1= newnu->bp;
941                                         while(b--) {
942                                                 select_bpoint(bp1, SELECT, flag, HIDDEN);
943                                                 bp1++;
944                                         }
945
946                                         if(nu->flagu & CU_CYCLIC) {
947                                                 if(starta!=0 || enda!=nu->pntsu-1) {
948                                                         newnu->flagu &= ~CU_CYCLIC;
949                                                 }
950                                         }
951
952                                         /* knots */
953                                         newnu->knotsu= NULL;
954                                         makeknots(newnu, 1, newnu->flagu>>1);
955                                 }
956                                 bp++;
957                         }
958                 }
959                 else {
960                         /* a rectangular area in nurb has to be selected */
961                         if(isNurbsel(nu)) {
962                                 usel= MEM_callocN(nu->pntsu, "adduplicateN4");
963                                 bp= nu->bp;
964                                 for(a=0; a<nu->pntsv; a++) {
965                                         for(b=0; b<nu->pntsu; b++, bp++) {
966                                                 if(bp->f1 & flag) usel[b]++;
967                                         }
968                                 }
969                                 newu= 0;
970                                 newv= 0;
971                                 for(a=0; a<nu->pntsu; a++) {
972                                         if(usel[a]) {
973                                                 if(newv==0 || usel[a]==newv) {
974                                                         newv= usel[a];
975                                                         newu++;
976                                                 }
977                                                 else {
978                                                         newv= 0;
979                                                         break;
980                                                 }
981                                         }
982                                 }
983                                 if(newu==0 || newv==0) {
984                                         printf("Can't duplicate Nurb\n");
985                                 }
986                                 else {
987
988                                         if(newu==1) SWAP(short, newu, newv);
989
990                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
991                                         memcpy(newnu, nu, sizeof(Nurb));
992                                         BLI_addtail(&editNurb, newnu);
993                                         set_actNurb(newnu);
994                                         newnu->pntsu= newu;
995                                         newnu->pntsv= newv;
996                                         newnu->bp =
997                                                 (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
998                                         clamp_nurb_order_u(newnu);
999                                         clamp_nurb_order_v(newnu);
1000                                         
1001                                         newnu->knotsu= newnu->knotsv= NULL;
1002                                         
1003                                         bp= newnu->bp;
1004                                         bp1= nu->bp;
1005                                         for(a=0; a<nu->pntsv; a++) {
1006                                                 for(b=0; b<nu->pntsu; b++, bp1++) {
1007                                                         if(bp1->f1 & flag) {
1008                                                                 memcpy(bp, bp1, sizeof(BPoint));
1009                                                                 select_bpoint(bp1, DESELECT, flag, HIDDEN);
1010                                                                 bp++;
1011                                                         }
1012                                                 }
1013                                         }
1014                                         if (check_valid_nurb_u(newnu)) {
1015                                                 if(nu->pntsu==newnu->pntsu && nu->knotsu) {
1016                                                         newnu->knotsu= MEM_dupallocN( nu->knotsu );
1017                                                 } else {
1018                                                         makeknots(newnu, 1, newnu->flagu>>1);
1019                                                 }
1020                                         }
1021                                         if (check_valid_nurb_v(newnu)) {
1022                                                 if(nu->pntsv==newnu->pntsv && nu->knotsv) {
1023                                                         newnu->knotsv= MEM_dupallocN( nu->knotsv );
1024                                                 } else {
1025                                                         makeknots(newnu, 2, newnu->flagv>>1);
1026                                                 }
1027                                         }
1028                                 }
1029                                 MEM_freeN(usel);
1030                         }
1031                 }
1032
1033                 nu= nu->prev;
1034         }
1035         
1036         /* actnu changed */
1037         allqueue(REDRAWBUTSEDIT, 0);
1038 }
1039
1040
1041 void switchdirectionNurb2(void)
1042 {
1043         Nurb *nu;
1044         
1045         if(G.vd==0 || !(G.obedit->lay & G.vd->lay))
1046                 return;
1047         
1048         for(nu= editNurb.first; nu; nu= nu->next) {
1049                 if( isNurbsel(nu) ) switchdirectionNurb(nu);
1050         }
1051         
1052         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1053
1054         allqueue(REDRAWVIEW3D, 0);
1055         BIF_undo_push("Switch direction");
1056 }
1057
1058 void switchdirection_knots(float *base, int tot)
1059 {
1060         float *fp1, *fp2, *tempf;
1061         int a;
1062         
1063         if(base==NULL || tot==0) return;
1064         
1065         /* reverse knots */
1066         a= tot;
1067         fp1= base;
1068         fp2= fp1+(a-1);
1069         a/= 2;
1070         while(fp1!=fp2 && a>0) {
1071                 SWAP(float, *fp1, *fp2);
1072                 a--;
1073                 fp1++; 
1074                 fp2--;
1075         }
1076         /* and make in increasing order again */
1077         a= tot;
1078         fp1= base;
1079         fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
1080         while(a--) {
1081                 fp2[0]= fabs(fp1[1]-fp1[0]);
1082                 fp1++;
1083                 fp2++;
1084         }
1085
1086         a= tot-1;
1087         fp1= base;
1088         fp2= tempf;
1089         fp1[0]= 0.0;
1090         fp1++;
1091         while(a--) {
1092                 fp1[0]= fp1[-1]+fp2[0];
1093                 fp1++;
1094                 fp2++;
1095         }
1096         MEM_freeN(tempf);
1097 }
1098
1099 void setweightNurb(void)
1100 {
1101         static float weight= 1.0f;
1102         extern ListBase editNurb;
1103         Nurb *nu;
1104         BezTriple *bezt;
1105         BPoint *bp;
1106         int a;
1107                                 
1108         if(fbutton(&weight, 0.0f, 1.0f, 10, 10, "Set Weight")) {
1109                 for(nu= editNurb.first; nu; nu= nu->next) {
1110                         if(nu->bezt) {
1111                                 for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1112                                         if(bezt->f2 & SELECT)
1113                                                 bezt->weight= weight;
1114                                 }
1115                         }
1116                         else if(nu->bp) {
1117                                 for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1118                                         if(bp->f1 & SELECT)
1119                                                 bp->weight= weight;
1120                                 }
1121                         }
1122                 }       
1123         }
1124         BIF_undo_push("Set Curve Weight");
1125         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
1126         allqueue(REDRAWVIEW3D, 0);
1127 }
1128
1129 void setradiusNurb( void )
1130 {
1131         static float radius= 1.0f;
1132         extern ListBase editNurb;
1133         Nurb *nu;
1134         BezTriple *bezt;
1135         BPoint *bp;
1136         int a;
1137         
1138         if(fbutton(&radius, 0.0001f, 10.0f, 10, 10, "Set Radius")) {
1139                 for(nu= editNurb.first; nu; nu= nu->next) {
1140                         if(nu->bezt) {
1141                                 for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1142                                         if(bezt->f2 & SELECT)
1143                                                 bezt->radius= radius;
1144                                 }
1145                         }
1146                         else if(nu->bp) {
1147                                 for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1148                                         if(bp->f1 & SELECT)
1149                                                 bp->radius= radius;
1150                                 }
1151                         }
1152                 }       
1153         }
1154         BIF_undo_push("Set Curve Radius");
1155         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
1156         allqueue(REDRAWVIEW3D, 0);
1157         allqueue(REDRAWBUTSALL, 0);
1158         allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
1159 }
1160
1161
1162 /* TODO, make smoothing distance based */
1163 void smoothradiusNurb( void )
1164 {
1165         extern ListBase editNurb;
1166         Nurb *nu;
1167         BezTriple *bezt;
1168         BPoint *bp;
1169         int a;
1170         
1171         /* use for smoothing */
1172         int last_sel;
1173         int start_sel, end_sel; /* selection indicies, inclusive */
1174         float start_rad, end_rad, fac, range;
1175         
1176         for(nu= editNurb.first; nu; nu= nu->next) {
1177                 if(nu->bezt) {
1178                         
1179                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1180                                 /* loop over selection segments of a curve, smooth each */
1181                                 
1182                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1183                                 start_sel = end_sel = -1;
1184                                 for(bezt=nu->bezt+last_sel, a=last_sel; a<nu->pntsu; a++, bezt++) {
1185                                         if(bezt->f2 & SELECT) {
1186                                                 start_sel = a;
1187                                                 break;
1188                                         }
1189                                 }
1190                                 /* incase there are no other selected verts */
1191                                 end_sel = start_sel;
1192                                 for(bezt=nu->bezt+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bezt++) {
1193                                         if((bezt->f2 & SELECT)==0) {
1194                                                 break;
1195                                         }
1196                                         end_sel = a;
1197                                 }
1198                                 
1199                                 if (start_sel == -1) {
1200                                         last_sel = nu->pntsu; /* next... */
1201                                 } else {
1202                                         last_sel = end_sel; /* before we modify it */
1203                                         
1204                                         /* now blend between start and end sel */
1205                                         start_rad = end_rad = -1.0;
1206                                         
1207                                         if (start_sel == end_sel) {
1208                                                 /* simple, only 1 point selected */
1209                                                 if (start_sel>0)                                                start_rad = (nu->bezt+start_sel-1)->radius;
1210                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bezt+start_sel+1)->radius;
1211                                                 
1212                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bezt+start_sel)->radius = (start_rad + end_rad)/2;
1213                                                 else if (start_rad >= 0.0)                              (nu->bezt+start_sel)->radius = start_rad;
1214                                                 else if (end_rad >= 0.0)                                (nu->bezt+start_sel)->radius = end_rad;
1215                                         } else {
1216                                                 /* if endpoints selected, then use them */
1217                                                 if (start_sel==0) {
1218                                                         start_rad = (nu->bezt+start_sel)->radius;
1219                                                         start_sel++; /* we dont want to edit the selected endpoint */
1220                                                 } else {
1221                                                         start_rad = (nu->bezt+start_sel-1)->radius;
1222                                                 }
1223                                                 if (end_sel==nu->pntsu-1) {
1224                                                         end_rad = (nu->bezt+end_sel)->radius;
1225                                                         end_sel--; /* we dont want to edit the selected endpoint */
1226                                                 } else {
1227                                                         end_rad = (nu->bezt+end_sel+1)->radius;
1228                                                 }
1229                                                 
1230                                                 /* Now Blend between the points */
1231                                                 range = (float)(end_sel - start_sel) + 2.0f;
1232                                                 for(bezt=nu->bezt+start_sel, a=start_sel; a<=end_sel; a++, bezt++) {
1233                                                         fac = (float)(1+a-start_sel) / range;
1234                                                         bezt->radius = start_rad*(1.0-fac) + end_rad*fac;
1235                                                 }
1236                                         }
1237                                 }
1238                         }
1239                 } else if (nu->bp) {
1240                         /* Same as above, keep these the same! */
1241                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1242                                 /* loop over selection segments of a curve, smooth each */
1243                                 
1244                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1245                                 start_sel = end_sel = -1;
1246                                 for(bp=nu->bp+last_sel, a=last_sel; a<nu->pntsu; a++, bp++) {
1247                                         if(bp->f1 & SELECT) {
1248                                                 start_sel = a;
1249                                                 break;
1250                                         }
1251                                 }
1252                                 /* incase there are no other selected verts */
1253                                 end_sel = start_sel;
1254                                 for(bp=nu->bp+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bp++) {
1255                                         if((bp->f1 & SELECT)==0) {
1256                                                 break;
1257                                         }
1258                                         end_sel = a;
1259                                 }
1260                                 
1261                                 if (start_sel == -1) {
1262                                         last_sel = nu->pntsu; /* next... */
1263                                 } else {
1264                                         last_sel = end_sel; /* before we modify it */
1265                                         
1266                                         /* now blend between start and end sel */
1267                                         start_rad = end_rad = -1.0;
1268                                         
1269                                         if (start_sel == end_sel) {
1270                                                 /* simple, only 1 point selected */
1271                                                 if (start_sel>0)                                                start_rad = (nu->bp+start_sel-1)->radius;
1272                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bp+start_sel+1)->radius;
1273                                                 
1274                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bp+start_sel)->radius = (start_rad + end_rad)/2;
1275                                                 else if (start_rad >= 0.0)                              (nu->bp+start_sel)->radius = start_rad;
1276                                                 else if (end_rad >= 0.0)                                (nu->bp+start_sel)->radius = end_rad;
1277                                         } else {
1278                                                 /* if endpoints selected, then use them */
1279                                                 if (start_sel==0) {
1280                                                         start_rad = (nu->bp+start_sel)->radius;
1281                                                         start_sel++; /* we dont want to edit the selected endpoint */
1282                                                 } else {
1283                                                         start_rad = (nu->bp+start_sel-1)->radius;
1284                                                 }
1285                                                 if (end_sel==nu->pntsu-1) {
1286                                                         end_rad = (nu->bp+end_sel)->radius;
1287                                                         end_sel--; /* we dont want to edit the selected endpoint */
1288                                                 } else {
1289                                                         end_rad = (nu->bp+end_sel+1)->radius;
1290                                                 }
1291                                                 
1292                                                 /* Now Blend between the points */
1293                                                 range = (float)(end_sel - start_sel) + 2.0f;
1294                                                 for(bp=nu->bp+start_sel, a=start_sel; a<=end_sel; a++, bp++) {
1295                                                         fac = (float)(1+a-start_sel) / range;
1296                                                         bp->radius = start_rad*(1.0-fac) + end_rad*fac;
1297                                                 }
1298                                         }
1299                                 }
1300                         }
1301                 }
1302         }
1303         BIF_undo_push("Smooth Curve Radius");
1304         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
1305         allqueue(REDRAWVIEW3D, 0);
1306         allqueue(REDRAWBUTSALL, 0);
1307         allqueue(REDRAWINFO, 1);        /* 1, because header->win==0! */
1308 }
1309
1310
1311
1312 /* **************** EDIT ************************ */
1313
1314 /* next == 1 -> select next             */
1315 /* next == -1 -> select previous        */
1316 /* cont == 1 -> select continuously     */
1317 /* selstatus, inverts behaviour         */
1318 static void select_adjacent_cp(short next, short cont, short selstatus)
1319 {
1320         Nurb *nu;
1321         BezTriple *bezt;
1322         BPoint *bp;
1323         int a;
1324         short lastsel= 0, sel=0;
1325         
1326         if(next==0) return;
1327         
1328         for(nu= editNurb.first; nu; nu= nu->next) {
1329                 lastsel=0;
1330                 if((nu->type & 7)==CU_BEZIER) {                 
1331                         a= nu->pntsu;
1332                         bezt= nu->bezt;
1333                         if(next < 0) bezt= (nu->bezt + (a-1));
1334                         while(a--) {
1335                                 if(a-abs(next) < 0) break;
1336                                 sel= 0;
1337                                 if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & SELECT) || (selstatus==0))) {
1338                                         bezt+=next;
1339                                         if(!(bezt->f2 & SELECT) || (selstatus==0)) {
1340                                                 sel= select_beztriple(bezt, selstatus, 1, VISIBLE);     
1341                                                 if((sel==1) && (cont==0)) lastsel= 1;
1342                                         }                                                       
1343                                 }
1344                                 else {
1345                                         bezt+=next;
1346                                         lastsel= 0;
1347                                 }
1348                                 /* move around in zigzag way so that we go through each */                              
1349                                 bezt-=(next-next/abs(next));                            
1350                         }
1351                 }
1352                 else {
1353                         a= nu->pntsu*nu->pntsv;
1354                         bp= nu->bp;
1355                         if(next < 0) bp= (nu->bp + (a-1));
1356                         while(a--) {
1357                                 if(a-abs(next) < 0) break;
1358                                 sel=0;
1359                                 if((lastsel==0) && (bp->hide==0) && ((bp->f1 & SELECT) || (selstatus==0))) {
1360                                         bp+=next;
1361                                         if(!(bp->f1 & SELECT) || (selstatus==0)) {
1362                                                 sel= select_bpoint(bp, selstatus, 1, VISIBLE);
1363                                                 if((sel==1) && (cont==0)) lastsel= 1;
1364                                         }                       
1365                                 }
1366                                 else {
1367                                         bp+=next;
1368                                         lastsel= 0;
1369                                 }
1370                                 /* move around in zigzag way so that we go through each */
1371                                 bp-=(next-next/abs(next));                              
1372                         }
1373                 }
1374         }
1375 }
1376
1377 static short nurb_has_selected_cps()
1378 {
1379         Nurb *nu;
1380         BezTriple *bezt;
1381         BPoint *bp;
1382         int a;
1383
1384         for(nu= editNurb.first; nu; nu= nu->next) {
1385                 if((nu->type & 7)==CU_BEZIER) {
1386                         a= nu->pntsu;
1387                         bezt= nu->bezt;
1388                         while(a--) {
1389                                 if(bezt->hide==0) {
1390                                         if((bezt->f1 & SELECT)
1391                                         || (bezt->f2 & SELECT)
1392                                         || (bezt->f3 & SELECT)) return 1;
1393                                 }
1394                                 bezt++;
1395                         }
1396                 }
1397                 else {
1398                         a= nu->pntsu*nu->pntsv;
1399                         bp= nu->bp;
1400                         while(a--) {
1401                                 if((bp->hide==0) && (bp->f1 & SELECT)) return 1;
1402                                 bp++;
1403                         }
1404                 }
1405         }
1406         
1407         return 0;
1408 }
1409
1410 void deselectall_nurb()
1411 {
1412         if(!G.vd || !(G.obedit->lay & G.vd->lay))
1413                 return;
1414
1415         if(nurb_has_selected_cps()) { /* deselect all */
1416                 selectend_nurb(FIRST, 0, DESELECT); /* set first control points as unselected */
1417                 select_adjacent_cp(1, 1, DESELECT); /* cascade selection */     
1418         }
1419         else { /* select all */
1420                 selectend_nurb(FIRST, 0, SELECT); /* set first control points as selected */
1421                 select_adjacent_cp(1, 1, SELECT); /* cascade selection */
1422         }
1423         
1424         countall();
1425         allqueue(REDRAWVIEW3D, 0);
1426         BIF_undo_push("Deselect all");
1427 }
1428
1429 void hideNurb(int swap)
1430 {
1431         Nurb *nu;
1432         BPoint *bp;
1433         BezTriple *bezt;
1434         int a, sel;
1435
1436         if(G.obedit==0) return;
1437
1438         BIF_undo_push("Hide");
1439
1440         for(nu= editNurb.first; nu; nu= nu->next) {
1441                 if((nu->type & 7)==CU_BEZIER) {
1442                         bezt= nu->bezt;
1443                         a= nu->pntsu;
1444                         sel= 0;
1445                         while(a--) {
1446                                 if(BEZSELECTED_HIDDENHANDLES(bezt)) {
1447                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
1448                                         bezt->hide= 1;
1449                                 }
1450                                 if(bezt->hide) sel++;
1451                                 bezt++;
1452                         }
1453                         if(sel==nu->pntsu) nu->hide= 1;
1454                 }
1455                 else {
1456                         bp= nu->bp;
1457                         a= nu->pntsu*nu->pntsv;
1458                         sel= 0;
1459                         while(a--) {
1460                                 if(swap==0 && (bp->f1 & SELECT)) {
1461                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
1462                                         bp->hide= 1;
1463                                 }
1464                                 else if(swap && (bp->f1 & SELECT)==0) {
1465                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
1466                                         bp->hide= 1;
1467                                 }
1468                                 if(bp->hide) sel++;
1469                                 bp++;
1470                         }
1471                         if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
1472                 }
1473         }
1474
1475         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1476         countall();
1477         allqueue(REDRAWVIEW3D, 0);
1478         allqueue(REDRAWBUTSEDIT, 0);
1479 }
1480
1481 void revealNurb()
1482 {
1483         Nurb *nu;
1484         BPoint *bp;
1485         BezTriple *bezt;
1486         int a;
1487
1488         if(G.obedit==0) return;
1489
1490         for(nu= editNurb.first; nu; nu= nu->next) {
1491                 nu->hide= 0;
1492                 if((nu->type & 7)==CU_BEZIER) {
1493                         bezt= nu->bezt;
1494                         a= nu->pntsu;
1495                         while(a--) {
1496                                 if(bezt->hide) {
1497                                         select_beztriple(bezt, SELECT, 1, HIDDEN);
1498                                         bezt->hide= 0;
1499                                 }
1500                                 bezt++;
1501                         }
1502                 }
1503                 else {
1504                         bp= nu->bp;
1505                         a= nu->pntsu*nu->pntsv;
1506                         while(a--) {
1507                                 if(bp->hide) {
1508                                         select_bpoint(bp, SELECT, 1, HIDDEN);
1509                                         bp->hide= 0;
1510                                 }
1511                                 bp++;
1512                         }
1513                 }
1514         }
1515
1516         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1517         countall();
1518         allqueue(REDRAWVIEW3D, 0);
1519         BIF_undo_push("Reveal");
1520
1521 }
1522
1523 void selectswapNurb()
1524 {
1525         Nurb *nu;
1526         BPoint *bp;
1527         BezTriple *bezt;
1528         int a;
1529
1530         if(G.obedit==0) return;
1531
1532         for(nu= editNurb.first; nu; nu= nu->next) {
1533                 if((nu->type & 7)==CU_BEZIER) {
1534                         bezt= nu->bezt;
1535                         a= nu->pntsu;
1536                         while(a--) {
1537                                 if(bezt->hide==0) {
1538                                         bezt->f2 ^= SELECT; /* always do the center point */
1539                                         if ((G.f & G_HIDDENHANDLES)==0) {
1540                                                 bezt->f1 ^= SELECT;
1541                                                 bezt->f3 ^= SELECT;
1542                                         }
1543                                 }
1544                                 bezt++;
1545                         }
1546                 }
1547                 else {
1548                         bp= nu->bp;
1549                         a= nu->pntsu*nu->pntsv;
1550                         while(a--) {
1551                                 swap_selection_bpoint(bp);
1552                                 bp++;
1553                         }
1554                 }
1555         }
1556
1557         countall();
1558         allqueue(REDRAWVIEW3D, 0);
1559         BIF_undo_push("Select swap");
1560
1561 }
1562
1563 /** Divide the line segments associated with the currently selected
1564  * curve nodes (Bezier or NURB). If there are no valid segment
1565  * selections within the current selection, nothing happens.
1566  *
1567  * @deffunc subdividenurb subdivideNurb(void)
1568  * @return Nothing
1569  * @param  None
1570 */
1571 void subdivideNurb()
1572 {
1573         Nurb *nu;
1574         BezTriple *prevbezt, *bezt, *beztnew, *beztn;
1575         BPoint *bp, *prevbp, *bpnew, *bpn;
1576         float vec[15];
1577         int a, b, sel, amount, *usel, *vsel;
1578
1579    // printf("*** subdivideNurb: entering subdivide\n");
1580
1581         for(nu= editNurb.first; nu; nu= nu->next) {
1582                 amount= 0;
1583                 if((nu->type & 7)==CU_BEZIER) {
1584         /* 
1585            Insert a point into a 2D Bezier curve. 
1586            Endpoints are preserved. Otherwise, all selected and inserted points are 
1587            newly created. Old points are discarded.
1588         */
1589                         /* count */
1590                         if(nu->flagu & CU_CYCLIC) {
1591                                 a= nu->pntsu;
1592                                 bezt= nu->bezt;
1593                                 prevbezt= bezt+(a-1);
1594                         }
1595                         else {
1596                                 a= nu->pntsu-1;
1597                                 prevbezt= nu->bezt;
1598                                 bezt= prevbezt+1;
1599                         }
1600                         while(a--) {
1601                                 if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) amount++;
1602                                 prevbezt= bezt;
1603                                 bezt++;
1604                         }
1605
1606                         if(amount) {
1607                                 /* insert */
1608                                 beztnew =
1609                                         (BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
1610                                 beztn= beztnew;
1611                                 if(nu->flagu & CU_CYCLIC) {
1612                                         a= nu->pntsu;
1613                                         bezt= nu->bezt;
1614                                         prevbezt= bezt+(a-1);
1615                                 }
1616                                 else {
1617                                         a= nu->pntsu-1;
1618                                         prevbezt= nu->bezt;
1619                                         bezt= prevbezt+1;
1620                                 }
1621                                 while(a--) {
1622                                         memcpy(beztn, prevbezt, sizeof(BezTriple));
1623                                         beztn++;
1624
1625                                         if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) {
1626                                                 memcpy(beztn, bezt, sizeof(BezTriple));
1627                                                 
1628                                                 /* midpoint subdividing */
1629                                                 VecMidf(vec, prevbezt->vec[1], prevbezt->vec[2]);
1630                                                 VecMidf(vec+3, prevbezt->vec[2], bezt->vec[0]);
1631                                                 VecMidf(vec+6, bezt->vec[0], bezt->vec[1]);
1632                                                 
1633                                                 VecMidf(vec+9, vec, vec+3);
1634                                                 VecMidf(vec+12, vec+3, vec+6);
1635                                                 
1636                                                 /* change handle of prev beztn */
1637                                                 VECCOPY((beztn-1)->vec[2], vec);
1638                                                 /* new point */
1639                                                 VECCOPY(beztn->vec[0], vec+9);
1640                                                 VecMidf(beztn->vec[1], vec+9, vec+12);
1641                                                 VECCOPY(beztn->vec[2], vec+12);
1642                                                 /* handle of next bezt */
1643                                                 if(a==0 && (nu->flagu & CU_CYCLIC)) {VECCOPY(beztnew->vec[0], vec+6);}
1644                                                 else {VECCOPY(bezt->vec[0], vec+6);}
1645                                                 
1646                                                 beztn->radius = (prevbezt->radius + bezt->radius)/2.0f;
1647                                                 beztn->weight = (prevbezt->weight + bezt->weight)/2.0f;
1648                                                 
1649                                                 beztn++;
1650                                         }
1651
1652                                         prevbezt= bezt;
1653                                         bezt++;
1654                                 }
1655                                 /* last point */
1656                                 if((nu->flagu & CU_CYCLIC)==0) memcpy(beztn, prevbezt, sizeof(BezTriple));
1657
1658                                 MEM_freeN(nu->bezt);
1659                                 nu->bezt= beztnew;
1660                                 nu->pntsu+= amount;
1661
1662                                 calchandlesNurb(nu);
1663                         }
1664                 } /* End of 'if((nu->type & 7)==CU_BEZIER)' */
1665                 else if (nu->pntsv==1) {
1666         /* 
1667            All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves 
1668            are handled together with the regular NURB plane division, as it 
1669            should be. I split it off just now, let's see if it is
1670            stable... nzc 30-5-'00
1671          */
1672                         /* count */
1673                         if(nu->flagu & CU_CYCLIC) {
1674                                 a= nu->pntsu*nu->pntsv;
1675                                 bp= nu->bp;
1676                                 prevbp= bp+(a-1);
1677                         }
1678                         else {
1679                                 a= nu->pntsu-1;
1680                                 prevbp= nu->bp;
1681                                 bp= prevbp+1;
1682                         }
1683                         while(a--) {
1684                                 if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount++;
1685                                 prevbp= bp;
1686                                 bp++;
1687                         }
1688
1689                         if(amount) {
1690                                 /* insert */
1691                                 bpnew =
1692                                         (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
1693                                 bpn= bpnew;
1694
1695                                 if(nu->flagu & CU_CYCLIC) {
1696                                         a= nu->pntsu;
1697                                         bp= nu->bp;
1698                                         prevbp= bp+(a-1);
1699                                 }
1700                                 else {
1701                                         a= nu->pntsu-1;
1702                                         prevbp= nu->bp;
1703                                         bp= prevbp+1;
1704                                 }
1705                                 while(a--) {
1706                                         memcpy(bpn, prevbp, sizeof(BPoint));
1707                                         bpn++;
1708
1709                                         if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) {
1710                  // printf("*** subdivideNurb: insert 'linear' point\n");
1711                                                 memcpy(bpn, bp, sizeof(BPoint));
1712                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1713                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1714                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1715                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1716                                                 bpn++;
1717
1718                                         }
1719                                         prevbp= bp;
1720                                         bp++;
1721                                 }
1722                                 if((nu->flagu & CU_CYCLIC)==0) memcpy(bpn, prevbp, sizeof(BPoint));     /* last point */
1723
1724                                 MEM_freeN(nu->bp);
1725                                 nu->bp= bpnew;
1726                                 nu->pntsu+= amount;
1727
1728                                 if(nu->type & 4) {
1729                                         makeknots(nu, 1, nu->flagu>>1);
1730                                 }
1731                         }
1732                 } /* End of 'else if(nu->pntsv==1)' */
1733                 else if((nu->type & 7)==CU_NURBS) {
1734         /* This is a very strange test ... */
1735         /** 
1736            Subdivide NURB surfaces - nzc 30-5-'00 -
1737            
1738              Subdivision of a NURB curve can be effected by adding a 
1739            control point (insertion of a knot), or by raising the
1740            degree of the functions used to build the NURB. The
1741            expression 
1742
1743                degree = #knots - #controlpoints + 1 (J Walter piece)
1744                degree = #knots - #controlpoints     (Blender
1745                                                       implementation)
1746                  ( this is confusing.... what is true? Another concern
1747                  is that the JW piece allows the curve to become
1748                  explicitly 1st order derivative discontinuous, while
1749                  this is not what we want here... )
1750
1751            is an invariant for a single NURB curve. Raising the degree
1752            of the NURB is done elsewhere; the degree is assumed
1753            constant during this opration. Degree is a property shared
1754            by all controlpoints in a curve (even though it is stored
1755            per control point - this can be misleading).
1756              Adding a knot is done by searching for the place in the
1757            knot vector where a certain knot value must be inserted, or
1758            by picking an appropriate knot value between two existing
1759            ones. The number of controlpoints that is influenced by the
1760            insertion depends on the order of the curve. A certain
1761            minimum number of knots is needed to form high-order
1762            curves, as can be seen from the equation above. In Blender,
1763            currently NURBs may be up to 6th order, so we modify at
1764            most 6 points. One point is added. For an n-degree curve,
1765            n points are discarded, and n+1 points inserted
1766            (so effectively, n points are modified).  (that holds for
1767            the JW piece, but it seems not for our NURBs)
1768               In practice, the knot spacing is copied, but the tail
1769            (the points following the insertion point) need to be
1770            offset to keep the knot series ascending. The knot series
1771            is always a series of monotonically ascending integers in
1772            Blender. When not enough control points are available to
1773            fit the order, duplicates of the endpoints are added as
1774            needed. 
1775         */
1776                         /* selection-arrays */
1777                         usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
1778                         vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
1779                         sel= 0;
1780
1781          /* Count the number of selected points. */
1782                         bp= nu->bp;
1783                         for(a=0; a<nu->pntsv; a++) {
1784                                 for(b=0; b<nu->pntsu; b++) {
1785                                         if(bp->f1 & SELECT) {
1786                                                 usel[b]++;
1787                                                 vsel[a]++;
1788                                                 sel++;
1789                                         }
1790                                         bp++;
1791                                 }
1792                         }
1793                         if( sel == (nu->pntsu*nu->pntsv) ) {    /* subdivide entire nurb */
1794            /* Global subdivision is a special case of partial
1795               subdivision. Strange it is considered separately... */
1796                                 bpn=bpnew= MEM_mallocN( (2*nu->pntsu-1)*(2*nu->pntsv-1)*sizeof(BPoint), "subdivideNurb4");
1797                                 bp= nu->bp;
1798                                 /* first subdivide rows */
1799                                 for(a=0; a<nu->pntsv; a++) {
1800                                         for(b=0; b<nu->pntsu; b++) {
1801                                                 *bpn= *bp;
1802                                                 bpn++; 
1803                                                 bp++;
1804                                                 if(b<nu->pntsu-1) {
1805                                                         *bpn= *bp;
1806                                                         prevbp= bp-1;
1807                                                         bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1808                                                         bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1809                                                         bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1810                                                         bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1811                                                         bpn++;
1812                                                 }
1813                                         }
1814                                         bpn+= (2*nu->pntsu-1);
1815                                 }
1816                                 /* now insert new */
1817                                 bpn= bpnew+(2*nu->pntsu-1);
1818                                 bp= bpnew+(4*nu->pntsu-2);
1819                                 prevbp= bpnew;
1820                                 for(a=1; a<nu->pntsv; a++) {
1821
1822                                         for(b=0; b<2*nu->pntsu-1; b++) {
1823                                                 *bpn= *bp;
1824                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1825                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1826                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1827                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1828                                                 bpn++; 
1829                                                 bp++; 
1830                                                 prevbp++;
1831                                         }
1832                                         bp+= (2*nu->pntsu-1);
1833                                         bpn+= (2*nu->pntsu-1);
1834                                         prevbp+= (2*nu->pntsu-1);
1835                                 }
1836                                 MEM_freeN(nu->bp);
1837                                 nu->bp= bpnew;
1838                                 nu->pntsu= 2*nu->pntsu-1;
1839                                 nu->pntsv= 2*nu->pntsv-1;
1840                                 makeknots(nu, 1, nu->flagu>>1);
1841                                 makeknots(nu, 2, nu->flagv>>1);
1842                         } /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */
1843                         else {
1844                                 /* subdivide in v direction? */
1845                                 sel= 0;
1846                                 for(a=0; a<nu->pntsv-1; a++) {
1847                                         if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel++;
1848                                 }
1849
1850                                 if(sel) {   /* V ! */
1851                                         bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4");
1852                                         bp= nu->bp;
1853                                         for(a=0; a<nu->pntsv; a++) {
1854                                                 for(b=0; b<nu->pntsu; b++) {
1855                                                         *bpn= *bp;
1856                                                         bpn++; 
1857                                                         bp++;
1858                                                 }
1859                                                 if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) {
1860                                                         prevbp= bp- nu->pntsu;
1861                                                         for(b=0; b<nu->pntsu; b++) {
1862                        /* 
1863                           This simple bisection must be replaces by a
1864                           subtle resampling of a number of points. Our 
1865                           task is made slightly easier because each
1866                           point in our curve is a separate data
1867                           node. (is it?)
1868                        */
1869                                                                 *bpn= *prevbp;
1870                                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1871                                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1872                                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1873                                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1874                                                                 bpn++;
1875                                                                 prevbp++;
1876                                                                 bp++;
1877                                                         }
1878                                                         bp-= nu->pntsu;
1879                                                 }
1880                                         }
1881                                         MEM_freeN(nu->bp);
1882                                         nu->bp= bpnew;
1883                                         nu->pntsv+= sel;
1884                                         makeknots(nu, 2, nu->flagv>>1);
1885                                 }
1886                                 else {
1887                                         /* or in u direction? */
1888                                         sel= 0;
1889                                         for(a=0; a<nu->pntsu-1; a++) {
1890                                                 if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel++;
1891                                         }
1892
1893                                         if(sel) {       /* U ! */
1894                  /* Inserting U points is sort of 'default' Flat curves only get */
1895                  /* U points inserted in them.                                   */
1896                                                 bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4");
1897                                                 bp= nu->bp;
1898                                                 for(a=0; a<nu->pntsv; a++) {
1899                                                         for(b=0; b<nu->pntsu; b++) {
1900                                                                 *bpn= *bp;
1901                                                                 bpn++; 
1902                                                                 bp++;
1903                                                                 if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) {
1904                           /* 
1905                              One thing that bugs me here is that the
1906                              orders of things are not the same as in
1907                              the JW piece. Also, this implies that we
1908                              handle at most 3rd order curves? I miss
1909                              some symmetry here...
1910                           */
1911                                                                         prevbp= bp- 1;
1912                                                                         *bpn= *prevbp;
1913                                                                         bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1914                                                                         bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1915                                                                         bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1916                                                                         bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1917                                                                         bpn++;
1918                                                                 }
1919                                                         }
1920                                                 }
1921                                                 MEM_freeN(nu->bp);
1922                                                 nu->bp= bpnew;
1923                                                 nu->pntsu+= sel;
1924                                                 makeknots(nu, 1, nu->flagu>>1); /* shift knots
1925                                                      forward */
1926                                         }
1927                                 }
1928                         }
1929                         MEM_freeN(usel); 
1930                         MEM_freeN(vsel);
1931
1932                 } /* End of 'if((nu->type & 7)==CU_NURBS)'  */
1933         }
1934
1935
1936         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1937
1938         countall();
1939         allqueue(REDRAWVIEW3D, 0);
1940         allqueue(REDRAWBUTSEDIT, 0);
1941         BIF_undo_push("Subdivide");
1942
1943 }
1944
1945 static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1946 {
1947         struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } *data = userData;
1948
1949         short flag;
1950         short temp;
1951
1952         if (bp) {
1953                 flag = bp->f1;
1954         } else {
1955                 if (beztindex==0) {
1956                         flag = bezt->f1;
1957                 } else if (beztindex==1) {
1958                         flag = bezt->f2;
1959                 } else {
1960                         flag = bezt->f3;
1961                 }
1962         }
1963
1964         temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
1965         if ((flag&1)==data->select) temp += 5;
1966         if (bezt && beztindex==1) temp += 3; /* middle points get a small disadvantage */
1967
1968         if (temp<data->dist) {
1969                 data->dist = temp;
1970
1971                 data->bp = bp;
1972                 data->bezt = bezt;
1973                 data->nurb = nu;
1974                 data->hpoint = bezt?beztindex:0;
1975         }
1976 }
1977
1978 static short findnearestNurbvert(short sel, Nurb **nurb, BezTriple **bezt, BPoint **bp)
1979 {
1980                 /* sel==1: selected gets a disadvantage */
1981                 /* in nurb and bezt or bp the nearest is written */
1982                 /* return 0 1 2: handlepunt */
1983         struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } data = {0};
1984
1985         data.dist = 100;
1986         data.hpoint = 0;
1987         data.select = sel;
1988         getmouseco_areawin(data.mval);
1989
1990         nurbs_foreachScreenVert(findnearestNurbvert__doClosest, &data);
1991
1992         *nurb = data.nurb;
1993         *bezt = data.bezt;
1994         *bp = data.bp;
1995
1996         return data.hpoint;
1997 }
1998
1999
2000 static void findselectedNurbvert(Nurb **nu, BezTriple **bezt, BPoint **bp)
2001 {
2002         /* in nu and (bezt or bp) selected are written if there's 1 sel.  */
2003         /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
2004         Nurb *nu1;
2005         BezTriple *bezt1;
2006         BPoint *bp1;
2007         int a;
2008
2009         *nu= 0;
2010         *bezt= 0;
2011         *bp= 0;
2012         for(nu1= editNurb.first; nu1; nu1= nu1->next) {
2013                 if((nu1->type & 7)==CU_BEZIER) {
2014                         bezt1= nu1->bezt;
2015                         a= nu1->pntsu;
2016                         while(a--) {
2017                                 if( (bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT) ) {
2018                                         if(*nu!=0 && *nu!= nu1) {
2019                                                 *nu= 0;
2020                                                 *bp= 0;
2021                                                 *bezt= 0;
2022                                                 return;
2023                                         }
2024                                         else if(*bezt || *bp) {
2025                                                 *bp= 0;
2026                                                 *bezt= 0;
2027                                         }
2028                                         else {
2029                                                 *bezt= bezt1;
2030                                                 *nu= nu1;
2031                                         }
2032                                 }
2033                                 bezt1++;
2034                         }
2035                 }
2036                 else {
2037                         bp1= nu1->bp;
2038                         a= nu1->pntsu*nu1->pntsv;
2039                         while(a--) {
2040                                 if( bp1->f1 & 1 ) {
2041                                         if(*nu!=0 && *nu!= nu1) {
2042                                                 *bp= 0;
2043                                                 *bezt= 0;
2044                                                 *nu= 0;
2045                                                 return;
2046                                         }
2047                                         else if(*bezt || *bp) {
2048                                                 *bp= 0;
2049                                                 *bezt= 0;
2050                                         }
2051                                         else {
2052                                                 *bp= bp1;
2053                                                 *nu= nu1;
2054                                         }
2055                                 }
2056                                 bp1++;
2057                         }
2058                 }
2059         }
2060 }
2061
2062 int convertspline(short type, Nurb *nu)
2063 {
2064         BezTriple *bezt;
2065         BPoint *bp;
2066         int a, c, nr;
2067
2068         if((nu->type & 7)==0) {         /* Poly */
2069                 if(type==CU_BEZIER) {                       /* to Bezier with vecthandles  */
2070                         nr= nu->pntsu;
2071                         bezt =
2072                                 (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
2073                         nu->bezt= bezt;
2074                         a= nr;
2075                         bp= nu->bp;
2076                         while(a--) {
2077                                 VECCOPY(bezt->vec[1], bp->vec);
2078                                 bezt->f1=bezt->f2=bezt->f3= bp->f1;
2079                                 bezt->h1= bezt->h2= HD_VECT;
2080                                 bezt->weight= bp->weight;
2081                                 bezt->radius= bp->radius;
2082                                 bp++;
2083                                 bezt++;
2084                         }
2085                         MEM_freeN(nu->bp);
2086                         nu->bp= 0;
2087                         nu->pntsu= nr;
2088                         nu->type &= ~7;
2089                         nu->type |= 1;
2090                         calchandlesNurb(nu);
2091                 }
2092                 else if(type==4) {                  /* to Nurb */
2093                         nu->type &= ~7;
2094                         nu->type+= 4;
2095                         nu->orderu= 4;
2096                         nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
2097                         nu->flagu += 4;
2098                         makeknots(nu, 1, nu->flagu>>1);
2099                         a= nu->pntsu*nu->pntsv;
2100                         bp= nu->bp;
2101                         while(a--) {
2102                                 bp->vec[3]= 1.0;
2103                                 bp++;
2104                         }
2105                 }
2106         }
2107         else if((nu->type & 7)==CU_BEZIER) {    /* Bezier */
2108                 if(type==0 || type==4) {            /* to Poly or Nurb */
2109                         nr= 3*nu->pntsu;
2110                         nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
2111                         a= nu->pntsu;
2112                         bezt= nu->bezt;
2113                         bp= nu->bp;
2114                         while(a--) {
2115                                 if(type==0 && bezt->h1==HD_VECT && bezt->h2==HD_VECT) {
2116                                         /* vector handle becomes 1 poly vertice */
2117                                         VECCOPY(bp->vec, bezt->vec[1]);
2118                                         bp->vec[3]= 1.0;
2119                                         bp->f1= bezt->f2;
2120                                         nr-= 2;
2121                                         bp->radius= bezt->radius;
2122                                         bp->weight= bezt->weight;
2123                                         bp++;
2124                                 }
2125                                 else {
2126                                         for(c=0;c<3;c++) {
2127                                                 VECCOPY(bp->vec, bezt->vec[c]);
2128                                                 bp->vec[3]= 1.0;
2129                                                 if(c==0) bp->f1= bezt->f1;
2130                                                 else if(c==1) bp->f1= bezt->f2;
2131                                                 else bp->f1= bezt->f3;
2132                                                 bp->radius= bezt->radius;
2133                                                 bp->weight= bezt->weight;
2134                                                 bp++;
2135                                         }
2136                                 }
2137                                 bezt++;
2138                         }
2139                         MEM_freeN(nu->bezt); 
2140                         nu->bezt= 0;
2141                         nu->pntsu= nr;
2142                         nu->pntsv= 1;
2143                         nu->orderu= 4;
2144                         nu->orderv= 1;
2145                         nu->type &= ~7;
2146                         nu->type+= type;
2147                         if(nu->flagu & CU_CYCLIC) c= nu->orderu-1; 
2148                         else c= 0;
2149                         if(type== 4) {
2150                                 nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
2151                                 nu->flagu += 4;
2152                                 makeknots(nu, 1, nu->flagu>>1);
2153                         }
2154                 }
2155         }
2156         else if( (nu->type & 7)==CU_NURBS) {
2157                 if(type==0) {                   /* to Poly */
2158                         nu->type &= ~7;
2159                         if(nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
2160                         nu->knotsu= NULL;
2161                         if(nu->knotsv) MEM_freeN(nu->knotsv);
2162                         nu->knotsv= NULL;
2163                 }
2164                 else if(type==CU_BEZIER) {              /* to Bezier */
2165                         nr= nu->pntsu/3;
2166
2167                         if(nr<2) 
2168                                 return 1;       /* conversion impossible */
2169                         else {
2170                                 bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
2171                                 nu->bezt= bezt;
2172                                 a= nr;
2173                                 bp= nu->bp;
2174                                 while(a--) {
2175                                         VECCOPY(bezt->vec[0], bp->vec);
2176                                         bezt->f1= bp->f1;
2177                                         bp++;
2178                                         VECCOPY(bezt->vec[1], bp->vec);
2179                                         bezt->f2= bp->f1;
2180                                         bp++;
2181                                         VECCOPY(bezt->vec[2], bp->vec);
2182                                         bezt->f3= bp->f1;
2183                                         bezt->radius= bp->radius;
2184                                         bezt->weight= bp->weight;
2185                                         bp++;
2186                                         bezt++;
2187                                 }
2188                                 MEM_freeN(nu->bp);
2189                                 nu->bp= 0;
2190                                 MEM_freeN(nu->knotsu);
2191                                 nu->knotsu= NULL;
2192                                 nu->pntsu= nr;
2193                                 nu->type &= ~7;
2194                                 nu->type+= 1;
2195                         }
2196                 }
2197         }
2198         return 0;
2199 }
2200
2201 void setsplinetype(short type)
2202 {
2203         Nurb *nu;
2204
2205         if(type==CU_CARDINAL || type==CU_BSPLINE) {
2206                 error("Not implemented yet");
2207                 return;
2208         }
2209         
2210         for(nu= editNurb.first; nu; nu= nu->next) {
2211                 if(isNurbsel(nu)) {
2212                         if (convertspline(type, nu))
2213                                 error("no conversion possible");
2214                 }
2215         }
2216         BIF_undo_push("Set spline type");
2217         
2218 }
2219
2220 /* ******************** SKINNING LOFTING!!! ******************** */
2221
2222 void rotate_direction_nurb(Nurb *nu)
2223 {
2224         BPoint *bp1, *bp2, *temp;
2225         int u, v;
2226         
2227         SWAP(short, nu->pntsu, nu->pntsv);
2228         SWAP(short, nu->orderu, nu->orderv);
2229         SWAP(short, nu->resolu, nu->resolv);
2230         SWAP(short, nu->flagu, nu->flagv);
2231         
2232         SWAP(float *, nu->knotsu, nu->knotsv);
2233         switchdirection_knots(nu->knotsv, KNOTSV(nu) );
2234         
2235         temp= MEM_dupallocN(nu->bp);
2236         bp1= nu->bp;
2237         for(v=0; v<nu->pntsv; v++) {
2238                 for(u=0; u<nu->pntsu; u++, bp1++) {
2239                         bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v;
2240                         *bp1= *bp2;
2241                 }
2242         }
2243
2244         MEM_freeN(temp);
2245 }
2246
2247 int is_u_selected(Nurb *nu, int u)
2248 {
2249         BPoint *bp;
2250         int v;
2251         
2252         /* what about resolu == 2? */
2253         bp= nu->bp+u;
2254         for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) {
2255                 if(v) if(bp->f1 & SELECT) return 1;
2256         }
2257         
2258         return 0;
2259 }
2260
2261 /* ******************************** */
2262
2263 typedef struct NurbSort {
2264         struct NurbSort *next, *prev;
2265         Nurb *nu;
2266         float vec[3];
2267 } NurbSort;
2268
2269 static ListBase nsortbase= {0, 0};
2270 /*  static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
2271
2272 void make_selection_list_nurb()
2273 {
2274         ListBase nbase= {0, 0};
2275         NurbSort *nus, *nustest, *headdo, *taildo;
2276         Nurb *nu;
2277         BPoint *bp;
2278         float dist, headdist, taildist;
2279         int a;
2280         
2281         for(nu= editNurb.first; nu; nu= nu->next) {
2282                 if( isNurbsel(nu) ) {
2283                         
2284                         nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort");
2285                         BLI_addhead(&nbase, nus);
2286                         nus->nu= nu;
2287                         
2288                         bp= nu->bp;
2289                         a= nu->pntsu;
2290                         while(a--) {
2291                                 VecAddf(nus->vec, nus->vec, bp->vec);
2292                                 bp++;
2293                         }
2294                         VecMulf(nus->vec, 1.0/(float)nu->pntsu);
2295                         
2296                         
2297                 }
2298         }
2299
2300         /* just add the first one */
2301         nus= nbase.first;
2302         BLI_remlink(&nbase, nus);
2303         BLI_addtail( &nsortbase, nus);
2304         
2305         /* now add, either at head or tail, the closest one */
2306         while(nbase.first) {
2307         
2308                 headdist= taildist= 1.0e30;
2309                 headdo= taildo= 0;
2310
2311                 nustest= nbase.first;
2312                 while(nustest) {
2313                         dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
2314
2315                         if(dist<headdist) {
2316                                 headdist= dist;
2317                                 headdo= nustest;
2318                         }
2319                         dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
2320
2321                         if(dist<taildist) {
2322                                 taildist= dist;
2323                                 taildo= nustest;
2324                         }
2325                         nustest= nustest->next;
2326                 }
2327                 
2328                 if(headdist<taildist) {
2329                         BLI_remlink(&nbase, headdo);
2330                         BLI_addhead(&nsortbase, headdo);
2331                 }
2332                 else {
2333                         BLI_remlink(&nbase, taildo);
2334                         BLI_addtail(&nsortbase, taildo);
2335                 }
2336         }
2337 }
2338
2339 void merge_2_nurb(Nurb *nu1, Nurb *nu2)
2340 {
2341         BPoint *bp, *bp1, *bp2, *temp;
2342         float  len1, len2;
2343         int    origu, u, v;
2344         
2345         /* first nurbs will be changed to make u = resolu-1 selected */
2346         /* 2nd nurbs will be changed to make u = 0 selected */
2347
2348         /* first nurbs: u = resolu-1 selected */
2349         
2350         if( is_u_selected(nu1, nu1->pntsu-1) );
2351         else {
2352                 rotate_direction_nurb(nu1);
2353                 if( is_u_selected(nu1, nu1->pntsu-1) );
2354                 else {
2355                         rotate_direction_nurb(nu1);
2356                         if( is_u_selected(nu1, nu1->pntsu-1) );
2357                         else {
2358                                 rotate_direction_nurb(nu1);
2359                                 if( is_u_selected(nu1, nu1->pntsu-1) );
2360                                 else {
2361                                         /* rotate again, now its OK! */
2362                                         if(nu1->pntsv!=1) rotate_direction_nurb(nu1);
2363                                         return;
2364                                 }
2365                         }
2366                 }
2367         }
2368         
2369         /* 2nd nurbs: u = 0 selected */
2370         if( is_u_selected(nu2, 0) );
2371         else {
2372                 rotate_direction_nurb(nu2);
2373                 if( is_u_selected(nu2, 0) );
2374                 else {
2375                         rotate_direction_nurb(nu2);
2376                         if( is_u_selected(nu2, 0) );
2377                         else {
2378                                 rotate_direction_nurb(nu2);
2379                                 if( is_u_selected(nu2, 0) );
2380                                 else {
2381                                         /* rotate again, now its OK! */
2382                                         if(nu1->pntsu==1) rotate_direction_nurb(nu1);
2383                                         if(nu2->pntsv!=1) rotate_direction_nurb(nu2);
2384                                         return;
2385                                 }
2386                         }
2387                 }
2388         }
2389         
2390         if( nu1->pntsv != nu2->pntsv ) {
2391                 error("Resolution doesn't match");
2392                 return;
2393         }
2394         
2395         /* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */
2396         /* maybe we need a 'v' flip of nu2? */
2397         
2398         bp1= nu1->bp+nu1->pntsu-1;
2399         bp2= nu2->bp;
2400         len1= 0.0;
2401         
2402         for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) {
2403                 len1+= VecLenf(bp1->vec, bp2->vec);
2404         }
2405
2406         bp1= nu1->bp + nu1->pntsu-1;
2407         bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1);
2408         len2= 0.0;
2409         
2410         for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) {
2411                 len2+= VecLenf(bp1->vec, bp2->vec);
2412         }
2413
2414         /* merge */
2415         origu= nu1->pntsu;
2416         nu1->pntsu+= nu2->pntsu;
2417         nu1->resolu+= nu2->pntsu;
2418         if(nu1->resolv < nu2->resolv) nu1->resolv= nu2->resolv;
2419         if(nu1->orderu<3) nu1->orderu++;
2420         if(nu1->orderv<3) nu1->orderv++;
2421         temp= nu1->bp;
2422         nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP");
2423         
2424         bp= nu1->bp;
2425         bp1= temp;
2426         
2427         for(v=0; v<nu1->pntsv; v++) {
2428                 
2429                 /* switch direction? */
2430                 if(len1<len2) bp2= nu2->bp + v*nu2->pntsu;
2431                 else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu;
2432
2433                 for(u=0; u<nu1->pntsu; u++, bp++) {
2434                         if(u<origu) {
2435                                 *bp= *bp1; bp1++;
2436                                 select_bpoint(bp, SELECT, 1, HIDDEN);
2437                         }
2438                         else {
2439                                 *bp= *bp2; bp2++;
2440                         }
2441                 }
2442         }
2443
2444         if((nu1->type & 7)==4) {
2445                 /* merge knots */
2446                 makeknots(nu1, 1, nu1->flagu>>1);
2447         
2448                 /* make knots, for merged curved for example */
2449                 makeknots(nu1, 2, nu1->flagv>>1);
2450         }
2451         
2452         MEM_freeN(temp);
2453         BLI_remlink(&editNurb, nu2);
2454         freeNurb(nu2);
2455 }
2456
2457 void merge_nurb()
2458 {
2459         NurbSort *nus1, *nus2;
2460         int ok= 1;
2461         
2462         make_selection_list_nurb();
2463         
2464         if(nsortbase.first == nsortbase.last) {
2465                 BLI_freelistN(&nsortbase);
2466                 error("Too few selections to merge");
2467                 return;
2468         }
2469         
2470         nus1= nsortbase.first;
2471         nus2= nus1->next;
2472
2473         /* resolution match, to avoid uv rotations */
2474         if(nus1->nu->pntsv==1) {
2475                 if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv);
2476                 else ok= 0;
2477         }
2478         else if(nus2->nu->pntsv==1) {
2479                 if(nus2->nu->pntsu==nus1->nu->pntsu || nus2->nu->pntsu==nus1->nu->pntsv);
2480                 else ok= 0;
2481         }
2482         else if( nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsv==nus2->nu->pntsv);
2483         else if( nus1->nu->pntsu==nus2->nu->pntsv || nus1->nu->pntsv==nus2->nu->pntsu);
2484         else {
2485                 ok= 0;
2486         }
2487         
2488         if(ok==0) {
2489                 error("Resolution doesn't match");
2490                 BLI_freelistN(&nsortbase);
2491                 return;
2492         }
2493         
2494         while(nus2) {
2495                 merge_2_nurb(nus1->nu, nus2->nu);
2496                 nus2= nus2->next;
2497         }
2498         
2499         BLI_freelistN(&nsortbase);
2500         
2501         countall();
2502         set_actNurb(NULL);
2503
2504         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2505
2506         allqueue(REDRAWVIEW3D, 0);
2507         allqueue(REDRAWBUTSEDIT, 0);
2508         BIF_undo_push("Merge");
2509         
2510 }
2511
2512
2513 void addsegment_nurb()
2514 {
2515         /* joins 2 curves */
2516         Nurb *nu, *nu1=0, *nu2=0;
2517         BezTriple *bezt;
2518         BPoint *bp;
2519         float *fp, offset;
2520         int a;
2521
2522         /* first decide if this is a surface merge! */
2523         if(G.obedit->type==OB_SURF) nu= editNurb.first;
2524         else nu= NULL;
2525         
2526         while(nu) {
2527                 if( isNurbsel(nu) ) {
2528                 
2529                         if(nu->pntsu>1 && nu->pntsv>1) break;
2530                         if(isNurbsel_count(nu)>1) break;
2531                         if(isNurbsel_count(nu)==1) {
2532                                 /* only 1 selected, not first or last, a little complex, but intuitive */
2533                                 if(nu->pntsv==1) {
2534                                         if( (nu->bp->f1 & SELECT) || ((nu->bp+nu->pntsu-1)->f1 & SELECT));
2535                                         else break;
2536                                 }
2537                         }
2538                 }
2539                 nu= nu->next;
2540         }
2541         if(nu) {
2542                 merge_nurb();
2543                 return;
2544         }
2545         
2546         /* find both nurbs and points, nu1 will be put behind nu2 */
2547         for(nu= editNurb.first; nu; nu= nu->next) {
2548                 if((nu->flagu & CU_CYCLIC)==0) {    /* not cyclic */
2549                         if( (nu->type & 7)==CU_BEZIER ) {
2550                                 bezt= nu->bezt;
2551                                 if(nu1==0) {
2552                                         if( BEZSELECTED_HIDDENHANDLES(bezt) ) nu1= nu;
2553                                         else {
2554                                                 bezt= bezt+(nu->pntsu-1);
2555                                                 if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
2556                                                         nu1= nu;
2557                                                         switchdirectionNurb(nu);
2558                                                 }
2559                                         }
2560                                 }
2561                                 else if(nu2==0) {
2562                                         if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
2563                                                 nu2= nu;
2564                                                 switchdirectionNurb(nu);
2565                                         }
2566                                         else {
2567                                                 bezt= bezt+(nu->pntsu-1);
2568                                                 if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
2569                                                         nu2= nu;
2570                                                 }
2571                                         }
2572                                 }
2573                                 else break;
2574                         }
2575                         else if(nu->pntsv==1) {
2576                                 bp= nu->bp;
2577                                 if(nu1==0) {
2578                                         if( bp->f1 & SELECT) nu1= nu;
2579                                         else {
2580                                                 bp= bp+(nu->pntsu-1);
2581                                                 if( bp->f1 & SELECT ) {
2582                                                         nu1= nu;
2583                                                         switchdirectionNurb(nu);
2584                                                 }
2585                                         }
2586                                 }
2587                                 else if(nu2==0) {
2588                                         if( bp->f1 & SELECT ) {
2589                                                 nu2= nu;
2590                                                 switchdirectionNurb(nu);
2591                                         }
2592                                         else {
2593                                                 bp= bp+(nu->pntsu-1);
2594                                                 if( bp->f1 & SELECT ) {
2595                                                         nu2= nu;
2596                                                 }
2597                                         }
2598                                 }
2599                                 else break;
2600                         }
2601                 }
2602         }
2603
2604         if((nu1 && nu2) && (nu1!=nu2)) {
2605                 if( nu1->type==nu2->type) {
2606                         if((nu1->type & 7)==CU_BEZIER) {
2607                                 bezt =
2608                                         (BezTriple*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BezTriple), "addsegmentN");
2609                                 memcpy(bezt, nu2->bezt, nu2->pntsu*sizeof(BezTriple));
2610                                 memcpy(bezt+nu2->pntsu, nu1->bezt, nu1->pntsu*sizeof(BezTriple));
2611                                 MEM_freeN(nu1->bezt);
2612                                 nu1->bezt= bezt;
2613                                 nu1->pntsu+= nu2->pntsu;
2614                                 BLI_remlink(&editNurb, nu2);
2615                                 freeNurb(nu2); nu2= NULL;
2616                                 calchandlesNurb(nu1);
2617                         }
2618                         else {
2619                                 bp =
2620                                         (BPoint*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BPoint), "addsegmentN2");
2621                                 memcpy(bp, nu2->bp, nu2->pntsu*sizeof(BPoint) );
2622                                 memcpy(bp+nu2->pntsu, nu1->bp, nu1->pntsu*sizeof(BPoint));
2623                                 MEM_freeN(nu1->bp);
2624                                 nu1->bp= bp;
2625
2626                                 a= nu1->pntsu+nu1->orderu;
2627
2628                                 nu1->pntsu+= nu2->pntsu;
2629                                 BLI_remlink(&editNurb, nu2);
2630
2631                                 /* now join the knots */
2632                                 if((nu1->type & 7)==4) {
2633                                         if(nu1->knotsu==NULL) {
2634                                                 makeknots(nu1, 1, nu1->flagu>>1);
2635                                         }
2636                                         else {
2637                                                 fp= MEM_mallocN(sizeof(float)*KNOTSU(nu1), "addsegment3");
2638                                                 memcpy(fp, nu1->knotsu, sizeof(float)*a);
2639                                                 MEM_freeN(nu1->knotsu);
2640                                                 nu1->knotsu= fp;
2641                                                 
2642                                                 
2643                                                 offset= nu1->knotsu[a-1] +1.0;
2644                                                 fp= nu1->knotsu+a;
2645                                                 for(a=0; a<nu2->pntsu; a++, fp++) {
2646                                                         if(nu2->knotsu) 
2647                                                                 *fp= offset+nu2->knotsu[a+1];
2648                                                         else 
2649                                                                 *fp = offset;
2650                                                 }
2651                                         }
2652                                 }
2653                                 freeNurb(nu2); nu2= NULL;
2654                         }
2655                 }
2656                 
2657                 set_actNurb(NULL);      /* for selected */
2658
2659                 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
2660
2661                 countall();
2662                 allqueue(REDRAWVIEW3D, 0);
2663                 allqueue(REDRAWBUTSEDIT, 0);
2664                 BIF_undo_push("Add segment");
2665         
2666         }
2667         else error("Can't make segment");
2668 }
2669
2670 void mouse_nurb()
2671 {
2672         Nurb *nu;
2673         BezTriple *bezt=0;
2674         BPoint *bp=0;
2675         short hand;
2676
2677         hand= findnearestNurbvert(1, &nu, &bezt, &bp);
2678
2679         if(bezt || bp) {
2680                 if((G.qual & LR_SHIFTKEY)==0) {
2681                 
2682                         setflagsNurb(0);
2683
2684                         if(bezt) {
2685
2686                                 if(hand==1) select_beztriple(bezt, SELECT, 1, HIDDEN);
2687                                 else if(hand==0) bezt->f1|= SELECT;
2688                                 else bezt->f3|= SELECT;
2689                         }
2690                         else {
2691                                 lastselbp= bp;
2692                                 select_bpoint(bp, SELECT, 1, HIDDEN);
2693                         }
2694
2695                         allqueue(REDRAWVIEW3D, 0);
2696                 }
2697                 else {
2698                         if(bezt) {
2699                                 if(hand==1) {
2700                                         if(bezt->f2 & SELECT) select_beztriple(bezt, DESELECT, 1, HIDDEN);
2701                                         else select_beztriple(bezt, SELECT, 1, HIDDEN);
2702                                 } else if(hand==0) {
2703                                         bezt->f1 ^= SELECT;
2704                                 } else {
2705                                         bezt->f3 ^= SELECT;
2706                                 }
2707                         }
2708                         else {
2709                                 if(bp->f1 & SELECT) select_bpoint(bp, DESELECT, 1, HIDDEN);
2710                                 else {
2711                                         select_bpoint(bp, SELECT, 1, HIDDEN);
2712                                         lastselbp= bp;
2713                                 }
2714                         }
2715
2716                         allqueue(REDRAWVIEW3D, 0);
2717
2718                 }
2719
2720                 countall();
2721         }
2722
2723         rightmouse_transform();
2724         
2725         if(nu!=get_actNurb()) {
2726                 set_actNurb(nu);
2727                 allqueue(REDRAWBUTSEDIT, 0);
2728         }
2729         
2730 }
2731
2732 /* from what I can gather, the mode==0 magic number spins and bridges the nurbs based on the 
2733  * orientation of the global 3d view (yuck yuck!) mode==1 does the same, but doesn't bridge up
2734  * up the new geometry, mode==2 now does the same as 0, but aligned to world axes, not the view.
2735 */
2736 static void spin_nurb(float *dvec, short mode)
2737 {
2738         Nurb *nu;
2739         float *curs, si,phi,n[3],q[4],cmat[3][3],tmat[3][3],imat[3][3];
2740         float cent[3],bmat[3][3], rotmat[3][3], scalemat1[3][3], scalemat2[3][3];
2741         float persmat[3][3], persinv[3][3];
2742         short a,ok;
2743         
2744         if(G.vd==0 || G.obedit==0 || G.obedit->type!=OB_SURF) return;
2745         if( (G.vd->lay & G.obedit->lay)==0 ) return;
2746
2747         if (mode != 2) Mat3CpyMat4(persmat, G.vd->viewmat);
2748         else Mat3One(persmat);
2749         Mat3Inv(persinv, persmat);
2750
2751         /* imat and center and size */
2752         Mat3CpyMat4(bmat, G.obedit->obmat);
2753         Mat3Inv(imat, bmat);
2754
2755         curs= give_cursor();
2756         VECCOPY(cent, curs);
2757         VecSubf(cent, cent, G.obedit->obmat[3]);
2758         Mat3MulVecfl(imat,cent);
2759
2760         if(dvec || mode==2) {
2761                 n[0]=n[1]= 0.0;
2762                 n[2]= 1.0;
2763         } else {
2764                 n[0]= G.vd->viewinv[2][0];
2765                 n[1]= G.vd->viewinv[2][1];
2766                 n[2]= G.vd->viewinv[2][2];
2767                 Normalize(n);
2768         }
2769
2770         phi= M_PI/8.0;
2771         q[0]= cos(phi);
2772         si= sin(phi);
2773         q[1]= n[0]*si;
2774         q[2]= n[1]*si;
2775         q[3]= n[2]*si;
2776         QuatToMat3(q, cmat);
2777         Mat3MulMat3(tmat, cmat, bmat);
2778         Mat3MulMat3(rotmat, imat, tmat);
2779
2780         Mat3One(scalemat1);
2781         scalemat1[0][0]= sqrt(2.0);
2782         scalemat1[1][1]= sqrt(2.0);
2783
2784         Mat3MulMat3(tmat,persmat,bmat);
2785         Mat3MulMat3(cmat,scalemat1,tmat);
2786         Mat3MulMat3(tmat,persinv,cmat);
2787         Mat3MulMat3(scalemat1,imat,tmat);
2788
2789         Mat3One(scalemat2);
2790         scalemat2[0][0]/= sqrt(2.0);
2791         scalemat2[1][1]/= sqrt(2.0);
2792
2793         Mat3MulMat3(tmat,persmat,bmat);
2794         Mat3MulMat3(cmat,scalemat2,tmat);
2795         Mat3MulMat3(tmat,persinv,cmat);
2796         Mat3MulMat3(scalemat2,imat,tmat);
2797
2798         ok= 1;
2799
2800         for(a=0;a<7;a++) {
2801                 if(mode==0 || mode==2) ok= extrudeflagNurb(1);
2802                 else adduplicateflagNurb(1);
2803                 if(ok==0) {
2804                         error("Can't spin");
2805                         break;
2806                 }
2807                 rotateflagNurb(1,cent,rotmat);
2808
2809                 if(mode==0 || mode==2) {
2810                         if( (a & 1)==0 ) {
2811                                 rotateflagNurb(1,cent,scalemat1);
2812                                 weightflagNurb(1, 0.25*sqrt(2.0), 1);
2813                         }
2814                         else {
2815                                 rotateflagNurb(1,cent,scalemat2);
2816                                 weightflagNurb(1, 4.0/sqrt(2.0), 1);
2817                         }
2818                 }
2819                 if(dvec) {
2820                         Mat3MulVecfl(bmat,dvec);
2821                         translateflagNurb(1,dvec);
2822                 }
2823         }
2824
2825         if(ok) {
2826                 for(nu= editNurb.first; nu; nu= nu->next) {
2827                         if(isNurbsel(nu)) {
2828                                 nu->orderv= 4;
2829                                 nu->flagv |= CU_CYCLIC;
2830                                 makeknots(nu, 2, nu->flagv>>1);
2831                         }
2832                 }
2833         }
2834         
2835 }
2836
2837 /* external one, for undo */
2838 void spinNurb(float *dvec, short mode)
2839 {
2840         spin_nurb(dvec, mode);
2841         BIF_undo_push("Spin");
2842 }
2843
2844 void addvert_Nurb(int mode)
2845 {
2846         Nurb *nu;
2847         BezTriple *bezt, *newbezt = NULL;
2848         BPoint *bp, *newbp = NULL;
2849         float *curs, mat[3][3],imat[3][3], temp[3];
2850
2851         if(G.obedit==0 || G.vd == 0) return;
2852         if( (G.vd->lay & G.obedit->lay)==0 ) return;
2853
2854         Mat3CpyMat4(mat, G.obedit->obmat);
2855         Mat3Inv(imat,mat);
2856
2857         findselectedNurbvert(&nu, &bezt, &bp);
2858         if(bezt==0 && bp==0) return;
2859
2860         if((nu->type & 7)==CU_BEZIER) {
2861                 /* which bezpoint? */
2862                 if(bezt== nu->bezt) {   /* first */
2863                         bezt->f1= bezt->f2= bezt->f3= 0;
2864                         newbezt =
2865                                 (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
2866                         memcpy(newbezt+1, bezt, nu->pntsu*sizeof(BezTriple));
2867                         *newbezt= *bezt;
2868                         newbezt->f1= newbezt->f2= newbezt->f3= SELECT;
2869                         if(newbezt->h1 >= 0) newbezt->h2= newbezt->h1;
2870                         else newbezt->h2= newbezt->h1= HD_ALIGN; /* does this ever happen? */
2871                         VECCOPY(temp, bezt->vec[1]);
2872                         MEM_freeN(nu->bezt);
2873                         nu->bezt= newbezt;
2874                         bezt= newbezt+1;
2875                 }
2876                 else if(bezt== (nu->bezt+nu->pntsu-1)) {  /* last */
2877                         bezt->f1= bezt->f2= bezt->f3= 0;
2878                         newbezt =
2879     &nb