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