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