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