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