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