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