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