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