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