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