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