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