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