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