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