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