* Shrink/Fatten for bevelled curves
[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->radius = (prevbezt->radius + bezt->radius)/2.0f;
1371                                                 beztn->weight = (prevbezt->weight + bezt->weight)/2.0f;
1372                                                 
1373                                                 beztn++;
1374                                         }
1375
1376                                         prevbezt= bezt;
1377                                         bezt++;
1378                                 }
1379                                 /* last point */
1380                                 if((nu->flagu & 1)==0) memcpy(beztn, prevbezt, sizeof(BezTriple));
1381
1382                                 MEM_freeN(nu->bezt);
1383                                 nu->bezt= beztnew;
1384                                 nu->pntsu+= amount;
1385
1386                                 calchandlesNurb(nu);
1387                         }
1388                 } /* End of 'if((nu->type & 7)==CU_BEZIER)' */
1389                 else if (nu->pntsv==1) {
1390         /* 
1391            All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves 
1392            are handled together with the regular NURB plane division, as it 
1393            should be. I split it off just now, let's see if it is
1394            stable... nzc 30-5-'00
1395          */
1396                         /* count */
1397                         if(nu->flagu & 1) {
1398                                 a= nu->pntsu*nu->pntsv;
1399                                 bp= nu->bp;
1400                                 prevbp= bp+(a-1);
1401                         }
1402                         else {
1403                                 a= nu->pntsu-1;
1404                                 prevbp= nu->bp;
1405                                 bp= prevbp+1;
1406                         }
1407                         while(a--) {
1408                                 if( (bp->f1 & 1) && (prevbp->f1 & 1) ) amount++;
1409                                 prevbp= bp;
1410                                 bp++;
1411                         }
1412
1413                         if(amount) {
1414                                 /* insert */
1415                                 bpnew =
1416                                         (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
1417                                 bpn= bpnew;
1418
1419                                 if(nu->flagu & 1) {
1420                                         a= nu->pntsu;
1421                                         bp= nu->bp;
1422                                         prevbp= bp+(a-1);
1423                                 }
1424                                 else {
1425                                         a= nu->pntsu-1;
1426                                         prevbp= nu->bp;
1427                                         bp= prevbp+1;
1428                                 }
1429                                 while(a--) {
1430                                         memcpy(bpn, prevbp, sizeof(BPoint));
1431                                         bpn++;
1432
1433                                         if( (bp->f1 & 1) && (prevbp->f1 & 1) ) {
1434                  // printf("*** subdivideNurb: insert 'linear' point\n");
1435                                                 memcpy(bpn, bp, sizeof(BPoint));
1436                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1437                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1438                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1439                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1440                                                 bpn++;
1441
1442                                         }
1443                                         prevbp= bp;
1444                                         bp++;
1445                                 }
1446                                 if((nu->flagu & 1)==0) memcpy(bpn, prevbp, sizeof(BPoint));     /* last point */
1447
1448                                 MEM_freeN(nu->bp);
1449                                 nu->bp= bpnew;
1450                                 nu->pntsu+= amount;
1451
1452                                 if(nu->type & 4) {
1453                                         makeknots(nu, 1, nu->flagu>>1);
1454                                 }
1455                         }
1456                 } /* End of 'else if(nu->pntsv==1)' */
1457                 else if((nu->type & 7)==CU_NURBS) {
1458         /* This is a very strange test ... */
1459         /** 
1460            Subdivide NURB surfaces - nzc 30-5-'00 -
1461            
1462              Subdivision of a NURB curve can be effected by adding a 
1463            control point (insertion of a knot), or by raising the
1464            degree of the functions used to build the NURB. The
1465            expression 
1466
1467                degree = #knots - #controlpoints + 1 (J Walter piece)
1468                degree = #knots - #controlpoints     (Blender
1469                                                       implementation)
1470                  ( this is confusing.... what is true? Another concern
1471                  is that the JW piece allows the curve to become
1472                  explicitly 1st order derivative discontinuous, while
1473                  this is not what we want here... )
1474
1475            is an invariant for a single NURB curve. Raising the degree
1476            of the NURB is done elsewhere; the degree is assumed
1477            constant during this opration. Degree is a property shared
1478            by all controlpoints in a curve (even though it is stored
1479            per control point - this can be misleading).
1480              Adding a knot is done by searching for the place in the
1481            knot vector where a certain knot value must be inserted, or
1482            by picking an appropriate knot value between two existing
1483            ones. The number of controlpoints that is influenced by the
1484            insertion depends on the order of the curve. A certain
1485            minimum number of knots is needed to form high-order
1486            curves, as can be seen from the equation above. In Blender,
1487            currently NURBs may be up to 6th order, so we modify at
1488            most 6 points. One point is added. For an n-degree curve,
1489            n points are discarded, and n+1 points inserted
1490            (so effectively, n points are modified).  (that holds for
1491            the JW piece, but it seems not for our NURBs)
1492               In practice, the knot spacing is copied, but the tail
1493            (the points following the insertion point) need to be
1494            offset to keep the knot series ascending. The knot series
1495            is always a series of monotonically ascending integers in
1496            Blender. When not enough control points are available to
1497            fit the order, duplicates of the endpoints are added as
1498            needed. 
1499         */
1500                         /* selection-arrays */
1501                         usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
1502                         vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
1503                         sel= 0;
1504
1505          /* Count the number of selected points. */
1506                         bp= nu->bp;
1507                         for(a=0; a<nu->pntsv; a++) {
1508                                 for(b=0; b<nu->pntsu; b++) {
1509                                         if(bp->f1 & 1) {
1510                                                 usel[b]++;
1511                                                 vsel[a]++;
1512                                                 sel++;
1513                                         }
1514                                         bp++;
1515                                 }
1516                         }
1517                         if( sel == (nu->pntsu*nu->pntsv) ) {    /* subdivide entire nurb */
1518            /* Global subdivision is a special case of partial
1519               subdivision. Strange it is considered separately... */
1520                                 bpn=bpnew= MEM_mallocN( (2*nu->pntsu-1)*(2*nu->pntsv-1)*sizeof(BPoint), "subdivideNurb4");
1521                                 bp= nu->bp;
1522                                 /* first subdivide rows */
1523                                 for(a=0; a<nu->pntsv; a++) {
1524                                         for(b=0; b<nu->pntsu; b++) {
1525                                                 *bpn= *bp;
1526                                                 bpn++; 
1527                                                 bp++;
1528                                                 if(b<nu->pntsu-1) {
1529                                                         *bpn= *bp;
1530                                                         prevbp= bp-1;
1531                                                         bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1532                                                         bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1533                                                         bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1534                                                         bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1535                                                         bpn++;
1536                                                 }
1537                                         }
1538                                         bpn+= (2*nu->pntsu-1);
1539                                 }
1540                                 /* now insert new */
1541                                 bpn= bpnew+(2*nu->pntsu-1);
1542                                 bp= bpnew+(4*nu->pntsu-2);
1543                                 prevbp= bpnew;
1544                                 for(a=1; a<nu->pntsv; a++) {
1545
1546                                         for(b=0; b<2*nu->pntsu-1; b++) {
1547                                                 *bpn= *bp;
1548                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1549                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1550                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1551                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1552                                                 bpn++; 
1553                                                 bp++; 
1554                                                 prevbp++;
1555                                         }
1556                                         bp+= (2*nu->pntsu-1);
1557                                         bpn+= (2*nu->pntsu-1);
1558                                         prevbp+= (2*nu->pntsu-1);
1559                                 }
1560                                 MEM_freeN(nu->bp);
1561                                 nu->bp= bpnew;
1562                                 nu->pntsu= 2*nu->pntsu-1;
1563                                 nu->pntsv= 2*nu->pntsv-1;
1564                                 makeknots(nu, 1, nu->flagu>>1);
1565                                 makeknots(nu, 2, nu->flagv>>1);
1566                         } /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */
1567                         else {
1568                                 /* subdivide in v direction? */
1569                                 sel= 0;
1570                                 for(a=0; a<nu->pntsv-1; a++) {
1571                                         if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel++;
1572                                 }
1573
1574                                 if(sel) {   /* V ! */
1575                                         bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4");
1576                                         bp= nu->bp;
1577                                         for(a=0; a<nu->pntsv; a++) {
1578                                                 for(b=0; b<nu->pntsu; b++) {
1579                                                         *bpn= *bp;
1580                                                         bpn++; 
1581                                                         bp++;
1582                                                 }
1583                                                 if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) {
1584                                                         prevbp= bp- nu->pntsu;
1585                                                         for(b=0; b<nu->pntsu; b++) {
1586                        /* 
1587                           This simple bisection must be replaces by a
1588                           subtle resampling of a number of points. Our 
1589                           task is made slightly easier because each
1590                           point in our curve is a separate data
1591                           node. (is it?)
1592                        */
1593                                                                 *bpn= *prevbp;
1594                                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1595                                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1596                                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1597                                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1598                                                                 bpn++;
1599                                                                 prevbp++;
1600                                                                 bp++;
1601                                                         }
1602                                                         bp-= nu->pntsu;
1603                                                 }
1604                                         }
1605                                         MEM_freeN(nu->bp);
1606                                         nu->bp= bpnew;
1607                                         nu->pntsv+= sel;
1608                                         makeknots(nu, 2, nu->flagv>>1);
1609                                 }
1610                                 else {
1611                                         /* or in u direction? */
1612                                         sel= 0;
1613                                         for(a=0; a<nu->pntsu-1; a++) {
1614                                                 if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel++;
1615                                         }
1616
1617                                         if(sel) {       /* U ! */
1618                  /* Inserting U points is sort of 'default' Flat curves only get */
1619                  /* U points inserted in them.                                   */
1620                                                 bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4");
1621                                                 bp= nu->bp;
1622                                                 for(a=0; a<nu->pntsv; a++) {
1623                                                         for(b=0; b<nu->pntsu; b++) {
1624                                                                 *bpn= *bp;
1625                                                                 bpn++; 
1626                                                                 bp++;
1627                                                                 if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) {
1628                           /* 
1629                              One thing that bugs me here is that the
1630                              orders of things are not the same as in
1631                              the JW piece. Also, this implies that we
1632                              handle at most 3rd order curves? I miss
1633                              some symmetry here...
1634                           */
1635                                                                         prevbp= bp- 1;
1636                                                                         *bpn= *prevbp;
1637                                                                         bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1638                                                                         bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1639                                                                         bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1640                                                                         bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1641                                                                         bpn++;
1642                                                                 }
1643                                                         }
1644                                                 }
1645                                                 MEM_freeN(nu->bp);
1646                                                 nu->bp= bpnew;
1647                                                 nu->pntsu+= sel;
1648                                                 makeknots(nu, 1, nu->flagu>>1); /* shift knots
1649                                                      forward */
1650                                         }
1651                                 }
1652                         }
1653                         MEM_freeN(usel); 
1654                         MEM_freeN(vsel);
1655
1656                 } /* End of 'if((nu->type & 7)==CU_NURBS)'  */
1657                 nu= nu->next;
1658         }
1659
1660
1661         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
1662
1663         countall();
1664         allqueue(REDRAWVIEW3D, 0);
1665         allqueue(REDRAWBUTSEDIT, 0);
1666         BIF_undo_push("Subdivide");
1667
1668 }
1669
1670 static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1671 {
1672         struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } *data = userData;
1673
1674         short flag;
1675         short temp;
1676
1677         if (bp) {
1678                 flag = bp->f1;
1679         } else {
1680                 if (beztindex==0) {
1681                         flag = bezt->f1;
1682                 } else if (beztindex==1) {
1683                         flag = bezt->f2;
1684                 } else {
1685                         flag = bezt->f3;
1686                 }
1687         }
1688
1689         temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
1690         if ((flag&1)==data->select) temp += 5;
1691         if (bezt && beztindex==1) temp += 3; /* middle points get a small disadvantage */
1692
1693         if (temp<data->dist) {
1694                 data->dist = temp;
1695
1696                 data->bp = bp;
1697                 data->bezt = bezt;
1698                 data->nurb = nu;
1699                 data->hpoint = bezt?beztindex:0;
1700         }
1701 }
1702
1703 static short findnearestNurbvert(short sel, Nurb **nurb, BezTriple **bezt, BPoint **bp)
1704 {
1705                 /* sel==1: selected gets a disadvantage */
1706                 /* in nurb and bezt or bp the nearest is written */
1707                 /* return 0 1 2: handlepunt */
1708         struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } data = {0};
1709
1710         data.dist = 100;
1711         data.hpoint = 0;
1712         data.select = sel;
1713         getmouseco_areawin(data.mval);
1714
1715         nurbs_foreachScreenVert(findnearestNurbvert__doClosest, &data);
1716
1717         *nurb = data.nurb;
1718         *bezt = data.bezt;
1719         *bp = data.bp;
1720
1721         return data.hpoint;
1722 }
1723
1724
1725 static void findselectedNurbvert(Nurb **nu, BezTriple **bezt, BPoint **bp)
1726 {
1727         /* in nu and (bezt or bp) selected are written if there's 1 sel.  */
1728         /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
1729         Nurb *nu1;
1730         BezTriple *bezt1;
1731         BPoint *bp1;
1732         int a;
1733
1734         *nu= 0;
1735         *bezt= 0;
1736         *bp= 0;
1737         nu1= editNurb.first;
1738         while(nu1) {
1739                 if((nu1->type & 7)==CU_BEZIER) {
1740                         bezt1= nu1->bezt;
1741                         a= nu1->pntsu;
1742                         while(a--) {
1743                                 if( (bezt1->f1 & 1) || (bezt1->f2 & 1) || (bezt1->f3 & 1) ) {
1744                                         if(*nu!=0 && *nu!= nu1) {
1745                                                 *nu= 0;
1746                                                 *bp= 0;
1747                                                 *bezt= 0;
1748                                                 return;
1749                                         }
1750                                         else if(*bezt || *bp) {
1751                                                 *bp= 0;
1752                                                 *bezt= 0;
1753                                         }
1754                                         else {
1755                                                 *bezt= bezt1;
1756                                                 *nu= nu1;
1757                                         }
1758                                 }
1759                                 bezt1++;
1760                         }
1761                 }
1762                 else {
1763                         bp1= nu1->bp;
1764                         a= nu1->pntsu*nu1->pntsv;
1765                         while(a--) {
1766                                 if( bp1->f1 & 1 ) {
1767                                         if(*nu!=0 && *nu!= nu1) {
1768                                                 *bp= 0;
1769                                                 *bezt= 0;
1770                                                 *nu= 0;
1771                                                 return;
1772                                         }
1773                                         else if(*bezt || *bp) {
1774                                                 *bp= 0;
1775                                                 *bezt= 0;
1776                                         }
1777                                         else {
1778                                                 *bp= bp1;
1779                                                 *nu= nu1;
1780                                         }
1781                                 }
1782                                 bp1++;
1783                         }
1784                 }
1785                 nu1= nu1->next;
1786         }
1787 }
1788
1789 int convertspline(short type, Nurb *nu)
1790 {
1791         BezTriple *bezt;
1792         BPoint *bp;
1793         int a, c, nr;
1794
1795         if((nu->type & 7)==0) {         /* Poly */
1796                 if(type==CU_BEZIER) {                       /* to Bezier with vecthandles  */
1797                         nr= nu->pntsu;
1798                         bezt =
1799                                 (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
1800                         nu->bezt= bezt;
1801                         a= nr;
1802                         bp= nu->bp;
1803                         while(a--) {
1804                                 VECCOPY(bezt->vec[1], bp->vec);
1805                                 bezt->f1=bezt->f2=bezt->f3= bp->f1;
1806                                 bezt->h1= bezt->h2= HD_VECT;
1807                                 bezt->weight= bp->weight;
1808                                 bezt->radius= bp->radius;
1809                                 bp++;
1810                                 bezt++;
1811                         }
1812                         MEM_freeN(nu->bp);
1813                         nu->bp= 0;
1814                         nu->pntsu= nr;
1815                         nu->type &= ~7;
1816                         nu->type |= 1;
1817                         calchandlesNurb(nu);
1818                 }
1819                 else if(type==4) {                  /* to Nurb */
1820                         nu->type &= ~7;
1821                         nu->type+= 4;
1822                         nu->orderu= 4;
1823                         nu->flagu &= 1;
1824                         nu->flagu += 4;
1825                         makeknots(nu, 1, nu->flagu>>1);
1826                         a= nu->pntsu*nu->pntsv;
1827                         bp= nu->bp;
1828                         while(a--) {
1829                                 bp->vec[3]= 1.0;
1830                                 bp++;
1831                         }
1832                 }
1833         }
1834         else if((nu->type & 7)==CU_BEZIER) {    /* Bezier */
1835                 if(type==0 || type==4) {            /* to Poly or Nurb */
1836                         nr= 3*nu->pntsu;
1837                         nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
1838                         a= nu->pntsu;
1839                         bezt= nu->bezt;
1840                         bp= nu->bp;
1841                         while(a--) {
1842                                 if(type==0 && bezt->h1==HD_VECT && bezt->h2==HD_VECT) {
1843                                         /* vector handle becomes 1 poly vertice */
1844                                         VECCOPY(bp->vec, bezt->vec[1]);
1845                                         bp->vec[3]= 1.0;
1846                                         bp->f1= bezt->f2;
1847                                         nr-= 2;
1848                                         bp->radius= bezt->radius;
1849                                         bp->weight= bezt->weight;
1850                                         bp++;
1851                                 }
1852                                 else {
1853                                         for(c=0;c<3;c++) {
1854                                                 VECCOPY(bp->vec, bezt->vec[c]);
1855                                                 bp->vec[3]= 1.0;
1856                                                 if(c==0) bp->f1= bezt->f1;
1857                                                 else if(c==1) bp->f1= bezt->f2;
1858                                                 else bp->f1= bezt->f3;
1859                                                 bp->radius= bezt->radius;
1860                                                 bp->weight= bezt->weight;
1861                                                 bp++;
1862                                         }
1863                                 }
1864                                 bezt++;
1865                         }
1866                         MEM_freeN(nu->bezt); 
1867                         nu->bezt= 0;
1868                         nu->pntsu= nr;
1869                         nu->pntsv= 1;
1870                         nu->orderu= 4;
1871                         nu->orderv= 1;
1872                         nu->type &= ~7;
1873                         nu->type+= type;
1874                         if(nu->flagu & 1) c= nu->orderu-1; 
1875                         else c= 0;
1876                         if(type== 4) {
1877                                 nu->flagu &= 1;
1878                                 nu->flagu += 4;
1879                                 makeknots(nu, 1, nu->flagu>>1);
1880                         }
1881                 }
1882         }
1883         else if( (nu->type & 7)==CU_NURBS) {
1884                 if(type==0) {                   /* to Poly */
1885                         nu->type &= ~7;
1886                         if(nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
1887                         nu->knotsu= 0;
1888                         if(nu->knotsv) MEM_freeN(nu->knotsv);
1889                         nu->knotsv= 0;
1890                 }
1891                 else if(type==CU_BEZIER) {              /* to Bezier */
1892                         nr= nu->pntsu/3;
1893
1894                         if(nr<2) 
1895                                 return 1;       /* conversion impossible */
1896                         else {
1897                                 bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
1898                                 nu->bezt= bezt;
1899                                 a= nr;
1900                                 bp= nu->bp;
1901                                 while(a--) {
1902                                         VECCOPY(bezt->vec[0], bp->vec);
1903                                         bezt->f1= bp->f1;
1904                                         bp++;
1905                                         VECCOPY(bezt->vec[1], bp->vec);
1906                                         bezt->f2= bp->f1;
1907                                         bp++;
1908                                         VECCOPY(bezt->vec[2], bp->vec);
1909                                         bezt->f3= bp->f1;
1910                                         bezt->radius= bp->radius;
1911                                         bezt->weight= bp->weight;
1912                                         bp++;
1913                                         bezt++;
1914                                 }
1915                                 MEM_freeN(nu->bp);
1916                                 nu->bp= 0;
1917                                 MEM_freeN(nu->knotsu);
1918                                 nu->knotsu= 0;
1919                                 nu->pntsu= nr;
1920                                 nu->type &= ~7;
1921                                 nu->type+= 1;
1922                         }
1923                 }
1924         }
1925         return 0;
1926 }
1927
1928 void setsplinetype(short type)
1929 {
1930         Nurb *nu;
1931
1932         if(type==CU_CARDINAL || type==CU_BSPLINE) {
1933                 error("Not implemented yet");
1934                 return;
1935         }
1936         
1937         nu= editNurb.first;
1938         while(nu) {
1939                 if(isNurbsel(nu)) {
1940                         if (convertspline(type, nu))
1941                                 error("no conversion possible");
1942                 }
1943                 nu= nu->next;
1944         }
1945         BIF_undo_push("Set spline type");
1946         
1947 }
1948
1949 /* ******************** SKINNING LOFTING!!! ******************** */
1950
1951 void rotate_direction_nurb(Nurb *nu)
1952 {
1953         BPoint *bp1, *bp2, *temp;
1954         int u, v;
1955         
1956         SWAP(short, nu->pntsu, nu->pntsv);
1957         SWAP(short, nu->orderu, nu->orderv);
1958         SWAP(short, nu->resolu, nu->resolv);
1959         SWAP(short, nu->flagu, nu->flagv);
1960         
1961         SWAP(float *, nu->knotsu, nu->knotsv);
1962         switchdirection_knots(nu->knotsv, KNOTSV(nu) );
1963         
1964         temp= MEM_dupallocN(nu->bp);
1965         bp1= nu->bp;
1966         for(v=0; v<nu->pntsv; v++) {
1967                 for(u=0; u<nu->pntsu; u++, bp1++) {
1968                         bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v;
1969                         *bp1= *bp2;
1970                 }
1971         }
1972
1973         MEM_freeN(temp);
1974 }
1975
1976 int is_u_selected(Nurb *nu, int u)
1977 {
1978         BPoint *bp;
1979         int v;
1980         
1981         /* what about resolu == 2? */
1982         bp= nu->bp+u;
1983         for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) {
1984                 if(v) if(bp->f1 & 1) return 1;
1985         }
1986         
1987         return 0;
1988 }
1989
1990 /* ******************************** */
1991
1992 typedef struct NurbSort {
1993         struct NurbSort *next, *prev;
1994         Nurb *nu;
1995         float vec[3];
1996 } NurbSort;
1997
1998 static ListBase nsortbase= {0, 0};
1999 /*  static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
2000
2001 void make_selection_list_nurb()
2002 {
2003         ListBase nbase= {0, 0};
2004         NurbSort *nus, *nustest, *headdo, *taildo;
2005         Nurb *nu;
2006         BPoint *bp;
2007         float dist, headdist, taildist;
2008         int a;
2009         
2010         nu= editNurb.first;
2011         while(nu) {
2012                 if( isNurbsel(nu) ) {
2013                         
2014                         nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort");
2015                         BLI_addhead(&nbase, nus);
2016                         nus->nu= nu;
2017                         
2018                         bp= nu->bp;
2019                         a= nu->pntsu;
2020                         while(a--) {
2021                                 VecAddf(nus->vec, nus->vec, bp->vec);
2022                                 bp++;
2023                         }
2024                         VecMulf(nus->vec, 1.0/(float)nu->pntsu);
2025                         
2026                         
2027                 }
2028                 nu= nu->next;
2029         }
2030
2031         /* just add the first one */
2032         nus= nbase.first;
2033         BLI_remlink(&nbase, nus);
2034         BLI_addtail( &nsortbase, nus);
2035         
2036         /* now add, either at head or tail, the closest one */
2037         while(nbase.first) {
2038         
2039                 headdist= taildist= 1.0e30;
2040                 headdo= taildo= 0;
2041
2042                 nustest= nbase.first;
2043                 while(nustest) {
2044                         dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
2045
2046                         if(dist<headdist) {
2047                                 headdist= dist;
2048                                 headdo= nustest;
2049                         }
2050                         dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
2051
2052                         if(dist<taildist) {
2053                                 taildist= dist;
2054                                 taildo= nustest;
2055                         }
2056                         nustest= nustest->next;
2057                 }
2058                 
2059                 if(headdist<taildist) {
2060                         BLI_remlink(&nbase, headdo);
2061                         BLI_addhead(&nsortbase, headdo);
2062                 }
2063                 else {
2064                         BLI_remlink(&nbase, taildo);
2065                         BLI_addtail(&nsortbase, taildo);
2066                 }
2067         }
2068 }
2069
2070 void merge_2_nurb(Nurb *nu1, Nurb *nu2)
2071 {
2072         BPoint *bp, *bp1, *bp2, *temp;
2073         float  len1, len2;
2074         int    origu, u, v;
2075         
2076         /* first nurbs will be changed to make u = resolu-1 selected */
2077         /* 2nd nurbs will be changed to make u = 0 selected */
2078
2079         /* first nurbs: u = resolu-1 selected */
2080         
2081         if( is_u_selected(nu1, nu1->pntsu-1) );
2082         else {
2083                 rotate_direction_nurb(nu1);
2084                 if( is_u_selected(nu1, nu1->pntsu-1) );
2085                 else {
2086                         rotate_direction_nurb(nu1);
2087                         if( is_u_selected(nu1, nu1->pntsu-1) );
2088                         else {
2089                                 rotate_direction_nurb(nu1);
2090                                 if( is_u_selected(nu1, nu1->pntsu-1) );
2091                                 else {
2092                                         /* rotate again, now its OK! */
2093                                         if(nu1->pntsv!=1) rotate_direction_nurb(nu1);
2094                                         return;
2095                                 }
2096                         }
2097                 }
2098         }
2099         
2100         /* 2nd nurbs: u = 0 selected */
2101         if( is_u_selected(nu2, 0) );
2102         else {
2103                 rotate_direction_nurb(nu2);
2104                 if( is_u_selected(nu2, 0) );
2105                 else {
2106                         rotate_direction_nurb(nu2);
2107                         if( is_u_selected(nu2, 0) );
2108                         else {
2109                                 rotate_direction_nurb(nu2);
2110                                 if( is_u_selected(nu2, 0) );
2111                                 else {
2112                                         /* rotate again, now its OK! */
2113                                         if(nu1->pntsu==1) rotate_direction_nurb(nu1);
2114                                         if(nu2->pntsv!=1) rotate_direction_nurb(nu2);
2115                                         return;
2116                                 }
2117                         }
2118                 }
2119         }
2120         
2121         if( nu1->pntsv != nu2->pntsv ) {
2122                 error("Resolution doesn't match");
2123                 return;
2124         }
2125         
2126         /* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */
2127         /* maybe we need a 'v' flip of nu2? */
2128         
2129         bp1= nu1->bp+nu1->pntsu-1;
2130         bp2= nu2->bp;
2131         len1= 0.0;
2132         
2133         for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) {
2134                 len1+= VecLenf(bp1->vec, bp2->vec);
2135         }
2136
2137         bp1= nu1->bp + nu1->pntsu-1;
2138         bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1);
2139         len2= 0.0;
2140         
2141         for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) {
2142                 len2+= VecLenf(bp1->vec, bp2->vec);
2143         }
2144
2145         /* merge */
2146         origu= nu1->pntsu;
2147         nu1->pntsu+= nu2->pntsu;
2148         nu1->resolu+= nu2->pntsu;
2149         if(nu1->resolv < nu2->resolv) nu1->resolv= nu2->resolv;
2150         if(nu1->orderu<3) nu1->orderu++;
2151         if(nu1->orderv<3) nu1->orderv++;
2152         temp= nu1->bp;
2153         nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP");
2154         
2155         bp= nu1->bp;
2156         bp1= temp;
2157         
2158         for(v=0; v<nu1->pntsv; v++) {
2159                 
2160                 /* switch direction? */
2161                 if(len1<len2) bp2= nu2->bp + v*nu2->pntsu;
2162                 else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu;
2163
2164                 for(u=0; u<nu1->pntsu; u++, bp++) {
2165                         if(u<origu) {
2166                                 *bp= *bp1; bp1++;
2167                                 bp->f1 &= ~SELECT;
2168                         }
2169                         else {
2170                                 *bp= *bp2; bp2++;
2171                         }
2172                 }
2173         }
2174
2175         if((nu1->type & 7)==4) {
2176                 /* merge knots */
2177                 makeknots(nu1, 1, nu1->flagu>>1);
2178         
2179                 /* make knots, for merged curved for example */
2180                 makeknots(nu1, 2, nu1->flagv>>1);
2181         }
2182         
2183         MEM_freeN(temp);
2184         BLI_remlink(&editNurb, nu2);
2185         freeNurb(nu2);
2186 }
2187
2188 void merge_nurb()
2189 {
2190         NurbSort *nus1, *nus2;
2191         int ok= 1;
2192         
2193         make_selection_list_nurb();
2194         
2195         if(nsortbase.first == nsortbase.last) {
2196                 BLI_freelistN(&nsortbase);
2197                 error("Too few selections to merge");
2198                 return;
2199         }
2200         
2201         nus1= nsortbase.first;
2202         nus2= nus1->next;
2203
2204         /* resolution match, to avoid uv rotations */
2205         if(nus1->nu->pntsv==1) {
2206                 if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv);
2207                 else ok= 0;
2208         }
2209         else if(nus2->nu->pntsv==1) {
2210                 if(nus2->nu->pntsu==nus1->nu->pntsu || nus2->nu->pntsu==nus1->nu->pntsv);
2211                 else ok= 0;
2212         }
2213         else if( nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsv==nus2->nu->pntsv);
2214         else if( nus1->nu->pntsu==nus2->nu->pntsv || nus1->nu->pntsv==nus2->nu->pntsu);
2215         else {
2216                 ok= 0;
2217         }
2218         
2219         if(ok==0) {
2220                 error("Resolution doesn't match");
2221                 BLI_freelistN(&nsortbase);
2222                 return;
2223         }
2224         
2225         while(nus2) {
2226                 merge_2_nurb(nus1->nu, nus2->nu);
2227                 nus2= nus2->next;
2228         }
2229         
2230         BLI_freelistN(&nsortbase);
2231         
2232         countall();
2233         lastnu= NULL;
2234
2235         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2236
2237         allqueue(REDRAWVIEW3D, 0);
2238         allqueue(REDRAWBUTSEDIT, 0);
2239         BIF_undo_push("Merge");
2240         
2241 }
2242
2243
2244 void addsegment_nurb()
2245 {
2246         /* joins 2 curves */
2247         Nurb *nu, *nu1=0, *nu2=0;
2248         BezTriple *bezt;
2249         BPoint *bp;
2250         float *fp, offset;
2251         int a;
2252
2253         /* first decide if this is a surface merge! */
2254         if(G.obedit->type==OB_SURF) nu= editNurb.first;
2255         else nu= NULL;
2256         
2257         while(nu) {
2258                 if( isNurbsel(nu) ) {
2259                 
2260                         if(nu->pntsu>1 && nu->pntsv>1) break;
2261                         if(isNurbsel_count(nu)>1) break;
2262                         if(isNurbsel_count(nu)==1) {
2263                                 /* only 1 selected, not first or last, a little complex, but intuitive */
2264                                 if(nu->pntsv==1) {
2265                                         if( (nu->bp->f1 & 1) || ((nu->bp+nu->pntsu-1)->f1 & 1));
2266                                         else break;
2267                                 }
2268                         }
2269                 }
2270                 nu= nu->next;
2271         }
2272         if(nu) {
2273                 merge_nurb();
2274                 return;
2275         }
2276         
2277         /* find both nurbs and points, nu1 will be put behind nu2 */
2278         nu= editNurb.first;
2279         while(nu) {
2280                 if((nu->flagu & 1)==0) {    /* not cyclic */
2281                         if( (nu->type & 7)==CU_BEZIER ) {
2282                                 bezt= nu->bezt;
2283                                 if(nu1==0) {
2284                                         if( BEZSELECTED(bezt) ) nu1= nu;
2285                                         else {
2286                                                 bezt= bezt+(nu->pntsu-1);
2287                                                 if( BEZSELECTED(bezt) ) {
2288                                                         nu1= nu;
2289                                                         switchdirectionNurb(nu);
2290                                                 }
2291                                         }
2292                                 }
2293                                 else if(nu2==0) {
2294                                         if( BEZSELECTED(bezt) ) {
2295                                                 nu2= nu;
2296                                                 switchdirectionNurb(nu);
2297                                         }
2298                                         else {
2299                                                 bezt= bezt+(nu->pntsu-1);
2300                                                 if( BEZSELECTED(bezt) ) {
2301                                                         nu2= nu;
2302                                                 }
2303                                         }
2304                                 }
2305                                 else break;
2306                         }
2307                         else if(nu->pntsv==1) {
2308                                 bp= nu->bp;
2309                                 if(nu1==0) {
2310                                         if( bp->f1 & 1) nu1= nu;
2311                                         else {
2312                                                 bp= bp+(nu->pntsu-1);
2313                                                 if( bp->f1 & 1 ) {
2314                                                         nu1= nu;
2315                                                         switchdirectionNurb(nu);
2316                                                 }
2317                                         }
2318                                 }
2319                                 else if(nu2==0) {
2320                                         if( bp->f1 & 1) {
2321                                                 nu2= nu;
2322                                                 switchdirectionNurb(nu);
2323                                         }
2324                                         else {
2325                                                 bp= bp+(nu->pntsu-1);
2326                                                 if( bp->f1 & 1 ) {
2327                                                         nu2= nu;
2328                                                 }
2329                                         }
2330                                 }
2331                                 else break;
2332                         }
2333                 }
2334                 nu= nu->next;
2335         }
2336
2337         if((nu1 && nu2) && (nu1!=nu2)) {
2338                 if( nu1->type==nu2->type) {
2339                         if((nu1->type & 7)==CU_BEZIER) {
2340                                 bezt =
2341                                         (BezTriple*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BezTriple), "addsegmentN");
2342                                 memcpy(bezt, nu2->bezt, nu2->pntsu*sizeof(BezTriple));
2343                                 memcpy(bezt+nu2->pntsu, nu1->bezt, nu1->pntsu*sizeof(BezTriple));
2344                                 MEM_freeN(nu1->bezt);
2345                                 nu1->bezt= bezt;
2346                                 nu1->pntsu+= nu2->pntsu;
2347                                 BLI_remlink(&editNurb, nu2);
2348                                 freeNurb(nu2);
2349                                 calchandlesNurb(nu1);
2350                         }
2351                         else {
2352                                 bp =
2353                                         (BPoint*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BPoint), "addsegmentN2");
2354                                 memcpy(bp, nu2->bp, nu2->pntsu*sizeof(BPoint) );
2355                                 memcpy(bp+nu2->pntsu, nu1->bp, nu1->pntsu*sizeof(BPoint));
2356                                 MEM_freeN(nu1->bp);
2357                                 nu1->bp= bp;
2358
2359                                 a= nu1->pntsu+nu1->orderu;
2360
2361                                 nu1->pntsu+= nu2->pntsu;
2362                                 BLI_remlink(&editNurb, nu2);
2363
2364                                 /* now join the knots */
2365                                 if((nu1->type & 7)==4) {
2366                                         if(nu1->knotsu==NULL) {
2367                                                 makeknots(nu1, 1, nu1->flagu>>1);
2368                                         }
2369                                         else {
2370                                                 fp= MEM_mallocN(sizeof(float)*KNOTSU(nu1), "addsegment3");
2371                                                 memcpy(fp, nu1->knotsu, sizeof(float)*a);
2372                                                 MEM_freeN(nu1->knotsu);
2373                                                 nu1->knotsu= fp;
2374                                                 
2375                                                 
2376                                                 offset= nu1->knotsu[a-1] +1.0;
2377                                                 fp= nu1->knotsu+a;
2378                                                 for(a=0; a<nu2->pntsu; a++, fp++) {
2379                                                         if(nu2->knotsu) 
2380                                                                 *fp= offset+nu2->knotsu[a+1];
2381                                                         else 
2382                                                                 *fp = offset;
2383                                                 }
2384                                         }
2385                                 }
2386                                 freeNurb(nu2);
2387                         }
2388                 }
2389                 
2390                 lastnu= NULL;   /* for selected */
2391
2392                 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
2393
2394                 countall();
2395                 allqueue(REDRAWVIEW3D, 0);
2396                 allqueue(REDRAWBUTSEDIT, 0);
2397                 BIF_undo_push("Add segment");
2398         
2399         }
2400         else error("Can't make segment");
2401 }
2402
2403 void mouse_nurb()
2404 {
2405         Nurb *nu;
2406         BezTriple *bezt=0;
2407         BPoint *bp=0;
2408         short hand;
2409
2410         hand= findnearestNurbvert(1, &nu, &bezt, &bp);
2411
2412         if(bezt || bp) {
2413                 if((G.qual & LR_SHIFTKEY)==0) {
2414                 
2415                         setflagsNurb(0);
2416
2417                         if(bezt) {
2418
2419                                 if(hand==1) {
2420                                         bezt->f1|= 1;
2421                                         bezt->f2|= 1;
2422                                         bezt->f3|= 1;
2423                                 }
2424                                 else if(hand==0) bezt->f1|= 1;
2425                                 else bezt->f3|= 1;
2426                         }
2427                         else {
2428                                 lastselbp= bp;
2429                                 bp->f1 |= 1;
2430                         }
2431
2432                         allqueue(REDRAWVIEW3D, 0);
2433                 }
2434                 else {
2435                         if(bezt) {
2436                                 if(hand==1) {
2437                                         if(bezt->f2 & 1) {
2438                                                 bezt->f1 &= ~1;
2439                                                 bezt->f2 &= ~1;
2440                                                 bezt->f3 &= ~1; 
2441                                         }
2442                                         else {
2443                                                 bezt->f1 |= 1;
2444                                                 bezt->f2 |= 1;
2445                                                 bezt->f3 |= 1;  
2446                                         }
2447                                 }
2448                                 else if(hand==0) {
2449                                         if(bezt->f1 & 1) {
2450                                                 bezt->f1 &= ~1; 
2451                                         }
2452                                         else {
2453                                                 bezt->f1 |= 1; 
2454                                         }
2455                                 }
2456                                 else {
2457                                         if(bezt->f3 & 1) { 
2458                                                 bezt->f3 &= ~1; 
2459                                         }
2460                                         else { 
2461                                                 bezt->f3 |= 1; 
2462                                         }
2463                                 }
2464                         }
2465                         else {
2466                                 if(bp->f1 & 1) bp->f1 &= ~1;
2467                                 else {
2468                                         bp->f1 |= 1;
2469                                         lastselbp= bp;
2470                                 }
2471                         }
2472
2473                         allqueue(REDRAWVIEW3D, 0);
2474
2475                 }
2476
2477                 countall();
2478         }
2479
2480         rightmouse_transform();
2481         
2482         if(nu!=lastnu) {
2483                 lastnu= nu;
2484                 allqueue(REDRAWBUTSEDIT, 0);
2485         }
2486         
2487 }
2488
2489 static void spin_nurb(float *dvec, short mode)
2490 {
2491         Nurb *nu;
2492         float *curs, si,phi,n[3],q[4],cmat[3][3],tmat[3][3],imat[3][3];
2493         float cent[3],bmat[3][3], rotmat[3][3], scalemat1[3][3], scalemat2[3][3];
2494         float persmat[3][3], persinv[3][3];
2495         short a,ok;
2496
2497         if(G.obedit==0 || G.obedit->type!=OB_SURF) return;
2498         if( (G.vd->lay & G.obedit->lay)==0 ) return;
2499
2500         Mat3CpyMat4(persmat, G.vd->viewmat);
2501         Mat3Inv(persinv, persmat);
2502
2503         /* imat and centre and size */
2504         Mat3CpyMat4(bmat, G.obedit->obmat);
2505         Mat3Inv(imat, bmat);
2506
2507         curs= give_cursor();
2508         VECCOPY(cent, curs);
2509         VecSubf(cent, cent, G.obedit->obmat[3]);
2510         Mat3MulVecfl(imat,cent);
2511
2512         if(dvec) {
2513                 n[0]=n[1]= 0.0;
2514                 n[2]= 1.0;
2515         } else {
2516                 n[0]= G.vd->viewinv[2][0];
2517                 n[1]= G.vd->viewinv[2][1];
2518                 n[2]= G.vd->viewinv[2][2];
2519                 Normalise(n);
2520         }
2521
2522         phi= M_PI/8.0;
2523         q[0]= cos(phi);
2524         si= sin(phi);
2525         q[1]= n[0]*si;
2526         q[2]= n[1]*si;
2527         q[3]= n[2]*si;
2528         QuatToMat3(q, cmat);
2529         Mat3MulMat3(tmat, cmat, bmat);
2530         Mat3MulMat3(rotmat, imat, tmat);
2531
2532         Mat3One(scalemat1);
2533         scalemat1[0][0]= sqrt(2.0);
2534         scalemat1[1][1]= sqrt(2.0);
2535
2536         Mat3MulMat3(tmat,persmat,bmat);
2537         Mat3MulMat3(cmat,scalemat1,tmat);
2538         Mat3MulMat3(tmat,persinv,cmat);
2539         Mat3MulMat3(scalemat1,imat,tmat);
2540
2541         Mat3One(scalemat2);
2542         scalemat2[0][0]/= sqrt(2.0);
2543         scalemat2[1][1]/= sqrt(2.0);
2544
2545         Mat3MulMat3(tmat,persmat,bmat);
2546         Mat3MulMat3(cmat,scalemat2,tmat);
2547         Mat3MulMat3(tmat,persinv,cmat);
2548         Mat3MulMat3(scalemat2,imat,tmat);
2549
2550         ok= 1;
2551
2552         for(a=0;a<7;a++) {
2553                 if(mode==0) ok= extrudeflagNurb(1);
2554                 else adduplicateflagNurb(1);
2555                 if(ok==0) {
2556                         error("Can't spin");
2557                         break;
2558                 }
2559                 rotateflagNurb(1,cent,rotmat);
2560
2561                 if(mode==0) {
2562                         if( (a & 1)==0 ) {
2563                                 rotateflagNurb(1,cent,scalemat1);
2564                                 weightflagNurb(1, 0.25*sqrt(2.0), 1);
2565                         }
2566                         else {
2567                                 rotateflagNurb(1,cent,scalemat2);
2568                                 weightflagNurb(1, 4.0/sqrt(2.0), 1);
2569                         }
2570                 }
2571                 if(dvec) {
2572                         Mat3MulVecfl(bmat,dvec);
2573                         translateflagNurb(1,dvec);
2574                 }
2575         }
2576
2577         if(ok) {
2578                 nu= editNurb.first;
2579                 while(nu) {
2580                         if(isNurbsel(nu)) {
2581                                 nu->orderv= 4;
2582                                 nu->flagv |= 1;
2583                                 makeknots(nu, 2, nu->flagv>>1);
2584                         }
2585                         nu= nu->next;
2586                 }
2587         }
2588         
2589 }
2590
2591 /* external one, for undo */
2592 void spinNurb(float *dvec, short mode)
2593 {
2594         spin_nurb(dvec, mode);
2595         BIF_undo_push("Spin");
2596 }
2597
2598 void addvert_Nurb(int mode)
2599 {
2600         Nurb *nu;
2601         BezTriple *bezt, *newbezt = NULL;
2602         BPoint *bp, *newbp = NULL;
2603         float *curs, mat[3][3],imat[3][3], temp[3];
2604
2605         if(G.obedit==0) return;
2606         if( (G.vd->lay & G.obedit->lay)==0 ) return;
2607
2608         Mat3CpyMat4(mat, G.obedit->obmat);
2609         Mat3Inv(imat,mat);
2610
2611         findselectedNurbvert(&nu, &bezt, &bp);
2612         if(bezt==0 && bp==0) return;
2613
2614         if((nu->type & 7)==CU_BEZIER) {
2615                 /* which bezpoint? */
2616                 if(bezt== nu->bezt) {   /* first */
2617                         bezt->f1= bezt->f2= bezt->f3= 0;
2618                         newbezt =
2619                                 (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
2620                         memcpy(newbezt+1, bezt, nu->pntsu*sizeof(BezTriple));
2621                         *newbezt= *bezt;
2622                         newbezt->f1= newbezt->f2= newbezt->f3= 1;
2623                         if(newbezt->h1 >= 0) newbezt->h2= newbezt->h1;
2624                         else newbezt->h2= newbezt->h1= HD_ALIGN; /* does this ever happen? */
2625                         VECCOPY(temp, bezt->vec[1]);
2626                         MEM_freeN(nu->bezt);
2627                         nu->bezt= newbezt;
2628                         bezt= newbezt+1;
2629                 }
2630                 else if(bezt== (nu->bezt+nu->pntsu-1)) {  /* last */
2631                         bezt->f1= bezt->f2= bezt->f3= 0;
2632                         newbezt =
2633                                 (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
2634                         memcpy(newbezt, nu->bezt, nu->pntsu*sizeof(BezTriple));
2635                         *(newbezt+nu->pntsu)= *bezt;
2636                         VECCOPY(temp, bezt->vec[1]);
2637                         MEM_freeN(nu->bezt);
2638                         nu->bezt= newbezt;
2639                         newbezt+= nu->pntsu;
2640                         newbezt->f1= newbezt->f2= newbezt->f3= 1;
2641                         if(newbezt->h1 >= 0) newbezt->h2= newbezt->h1;
2642                         else newbezt->h2= newbezt->h1= HD_ALIGN; /* does this ever happen? */
2643                         bezt= nu->bezt+nu->pntsu-1;
2644                 }
2645                 else bezt= 0;
2646
2647                 if(bezt) {
2648                         nu->pntsu++;
2649                         
2650                         if(mode=='e') {
2651                                 VECCOPY(newbezt->vec[0], bezt->vec[0]);
2652                                 VECCOPY(newbezt->vec[1], bezt->vec[1]);
2653                                 VECCOPY(newbezt->vec[2], bezt->vec[2]);
2654                         }
2655                         else {
2656                                 curs= give_cursor();
2657                         
2658                                 VECCOPY(newbezt->vec[1], curs);
2659                                 VecSubf(newbezt->vec[1],newbezt->vec[1],G.obedit->obmat[3]);
2660                                 Mat3MulVecfl(imat,newbezt->vec[1]);
2661                                 VecSubf(temp, newbezt->vec[1],temp);
2662                                 VecAddf(newbezt->vec[0], bezt->vec[0],temp);
2663                                 VecAddf(newbezt->vec[2], bezt->vec[2],temp);
2664                                 calchandlesNurb(nu);
2665                         }
2666                 }
2667         }
2668         else if(nu->pntsv==1) {
2669                 /* which b-point? */
2670                 if(bp== nu->bp) {   /* first */
2671                         bp->f1= 0;
2672                         newbp =
2673                                 (BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb3");
2674                         memcpy(newbp+1, bp, nu->pntsu*sizeof(BPoint));
2675                         *newbp= *bp;
2676                         newbp->f1= 1;
2677                         MEM_freeN(nu->bp);
2678                         nu->bp= newbp;
2679                 }
2680                 else if(bp== (nu->bp+nu->pntsu-1)) {  /* last */
2681                         bp->f1= 0;
2682                         newbp =
2683                                 (BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb4");
2684                         memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint));
2685                         *(newbp+nu->pntsu)= *bp;
2686                         MEM_freeN(nu->bp);
2687                         nu->bp= newbp;
2688                         newbp+= nu->pntsu;
2689                         newbp->f1= 1;
2690                 }
2691                 else bp= 0;
2692
2693                 if(bp) {
2694                         nu->pntsu++;
2695
2696                         if(nu->resolu<3) nu->resolu++;
2697                         makeknots(nu, 1, nu->flagu>>1);
2698
2699                         if(mode=='e') {
2700                                 VECCOPY(newbp->vec, bp->vec);
2701                         }
2702                         else {
2703                                 curs= give_cursor();
2704                         
2705                                 VECCOPY(newbp->vec, curs);
2706                                 VecSubf(newbp->vec, newbp->vec, G.obedit->obmat[3]);
2707                                 Mat3MulVecfl(imat,newbp->vec);
2708                                 newbp->vec[3]= 1.0;
2709                         }
2710                 }
2711         }
2712
2713         test2DNurb(nu);
2714         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2715         countall();
2716         allqueue(REDRAWVIEW3D, 0);
2717         allqueue(REDRAWBUTSEDIT, 0);
2718
2719         if(mode=='e') {
2720                 BIF_TransformSetUndo("Extrude");
2721                 initTransform(TFM_TRANSLATION, CTX_NO_PET);
2722                 Transform();
2723         }
2724         else while(get_mbut()&R_MOUSE) BIF_wait_for_statechange();
2725
2726         if(mode!='e') {
2727                 /* dependencies with other objects, should become event */
2728                 BIF_undo_push("Add vertex");
2729         
2730         }
2731 }
2732
2733 void extrude_nurb()
2734 {
2735         Nurb *nu;
2736         int ok= 0;
2737
2738         if(G.obedit && G.obedit->type==OB_SURF) {
2739
2740                 /* first test: curve? */
2741                 nu= editNurb.first;
2742                 while(nu) {
2743                         if(nu->pntsv==1 && isNurbsel_count(nu)==1 ) break;
2744                         nu= nu->next;
2745                 }
2746                 if(nu) {
2747                         addvert_Nurb('e');
2748                 }
2749                 else {
2750
2751
2752                         ok= extrudeflagNurb(1); /* '1'= flag */
2753                 
2754                         if(ok) {
2755                                 DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2756                                 countall();
2757                                 BIF_TransformSetUndo("Extrude");
2758                                 initTransform(TFM_TRANSLATION, CTX_NO_PET);
2759                                 Transform();
2760                         }
2761                 }
2762         }
2763 }
2764
2765
2766
2767 void makecyclicNurb()
2768 {
2769         Nurb *nu;
2770         BezTriple *bezt;
2771         BPoint *bp;
2772         float *fp;
2773         int a, b, cyclmode=0;
2774
2775         nu= editNurb.first;
2776         while(nu) {
2777                 if( nu->pntsu>1 || nu->pntsv>1) {
2778                         if( (nu->type & 7)==0 ) {
2779                                 a= nu->pntsu;
2780                                 bp= nu->bp;
2781                                 while(a--) {
2782                                         if( bp->f1 & 1 ) {
2783                                                 if(nu->flagu & CU_CYCLIC) nu->flagu--;
2784                                                 else nu->flagu++;
2785                                                 break;
2786                                         }
2787                                         bp++;
2788                                 }
2789                         }
2790                         else if( (nu->type & 7)==CU_BEZIER ) {
2791                                 a= nu->pntsu;
2792                                 bezt= nu->bezt;
2793                                 while(a--) {
2794                                         if( BEZSELECTED(bezt) ) {
2795                                                 if(nu->flagu & CU_CYCLIC) nu->flagu--;
2796                                                 else nu->flagu++;
2797                                                 break;
2798                                         }
2799                                         bezt++;
2800                                 }
2801                                 calchandlesNurb(nu);
2802                         }
2803                         else if(nu->pntsv==1 && (nu->type & 7)==CU_NURBS) {
2804                                 a= nu->pntsu;
2805                                 bp= nu->bp;
2806                                 while(a--) {
2807                                         if( bp->f1 & 1 ) {
2808                                                 if(nu->flagu & CU_CYCLIC) nu->flagu--;
2809                                                 else {
2810                                                         nu->flagu++;
2811                                                         nu->flagu &= ~2;        /* endpoint flag, fixme */
2812                                                         fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN");
2813                                                         b= (nu->orderu+nu->pntsu);
2814                                                         memcpy(fp, nu->knotsu, sizeof(float)*b);
2815                                                         MEM_freeN(nu->knotsu);
2816                                                         nu->knotsu= fp;
2817                                                         
2818                                                         makeknots(nu, 1, 0);    /* 1==u  0==uniform */
2819                                                         
2820                                                 }
2821                                                 break;
2822                                         }
2823                                         bp++;
2824                                 }
2825                         }
2826                         else if(nu->type==CU_NURBS) {
2827                                 if(cyclmode==0) {
2828                                         cyclmode= pupmenu("Toggle %t|cyclic U%x1|cyclic V%x2");
2829                                         if(cyclmode < 1) return;
2830                                 }
2831                                 a= nu->pntsu*nu->pntsv;
2832                                 bp= nu->bp;
2833                                 while(a--) {
2834         
2835                                         if( bp->f1 & 1) {
2836                                                 if(cyclmode==1 && nu->pntsu>1) {
2837                                                         if(nu->flagu & CU_CYCLIC) nu->flagu--;
2838                                                         else {
2839                                                                 nu->flagu++;
2840                                                                 fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN");
2841                                                                 b= (nu->orderu+nu->pntsu);
2842                                                                 memcpy(fp, nu->knotsu, sizeof(float)*b);
2843                                                                 MEM_freeN(nu->knotsu);
2844                                                                 nu->knotsu= fp;
2845                                                                 
2846                                                                 makeknots(nu, 1, 0);    /* 1==u  0==uniform */
2847                                                         }
2848                                                 }
2849                                                 if(cyclmode==2 && nu->pntsv>1) {
2850                                                         if(nu->flagv & 1) nu->flagv--;
2851                                                         else {
2852                                                                 nu->flagv++;
2853                                                                 fp= MEM_mallocN(sizeof(float)*KNOTSV(nu), "makecyclicN");
2854                                                                 b= (nu->orderv+nu->pntsv);
2855                                                                 memcpy(fp, nu->knotsv, sizeof(float)*b);
2856                                                                 MEM_freeN(nu->knotsv);
2857                                                                 nu->knotsv= fp;
2858                                                                 
2859                                                                 makeknots(nu, 2, 0);    /* 2==v  0==uniform */
2860                                                         }
2861                                                 }
2862                                                 break;
2863                                         }
2864                                         bp++;
2865                                 }
2866         
2867                         }
2868                 }
2869                 nu= nu->next;
2870         }
2871         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
2872         BIF_undo_push("Cyclic");
2873 }
2874
2875 void selectconnected_nurb()
2876 {
2877         Nurb *nu;
2878         BezTriple *bezt;
2879         BPoint *bp;
2880         int a;
2881
2882         findnearestNurbvert(1, &nu, &bezt, &bp);
2883         if(bezt) {
2884                 a= nu->pntsu;
2885                 bezt= nu->bezt;
2886                 while(a--) {
2887                         if(bezt->hide==0) {
2888                                 if(G.qual & LR_SHIFTKEY) {
2889                                         bezt->f1 &= ~1;
2890