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