remove unused includes
[blender.git] / source / blender / editors / curve / editcurve.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 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
2788                                  is that the JW piece allows the curve to become
2789                                  explicitly 1st order derivative discontinuous, while
2790                                  this is not what we want here... )
2791
2792                    is an invariant for a single NURB curve. Raising the degree
2793                    of the NURB is done elsewhere; the degree is assumed
2794                    constant during this opration. Degree is a property shared
2795                    by all controlpoints in a curve (even though it is stored
2796                    per control point - this can be misleading).
2797                          Adding a knot is done by searching for the place in the
2798                    knot vector where a certain knot value must be inserted, or
2799                    by picking an appropriate knot value between two existing
2800                    ones. The number of controlpoints that is influenced by the
2801                    insertion depends on the order of the curve. A certain
2802                    minimum number of knots is needed to form high-order
2803                    curves, as can be seen from the equation above. In Blender,
2804                    currently NURBs may be up to 6th order, so we modify at
2805                    most 6 points. One point is added. For an n-degree curve,
2806                    n points are discarded, and n+1 points inserted
2807                    (so effectively, n points are modified).  (that holds for
2808                    the JW piece, but it seems not for our NURBs)
2809                           In practice, the knot spacing is copied, but the tail
2810                    (the points following the insertion point) need to be
2811                    offset to keep the knot series ascending. The knot series
2812                    is always a series of monotonically ascending integers in
2813                    Blender. When not enough control points are available to
2814                    fit the order, duplicates of the endpoints are added as
2815                    needed. 
2816                 */
2817                         /* selection-arrays */
2818                         usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
2819                         vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
2820                         sel= 0;
2821
2822                  /* Count the number of selected points. */
2823                         bp= nu->bp;
2824                         for(a=0; a<nu->pntsv; a++) {
2825                                 for(b=0; b<nu->pntsu; b++) {
2826                                         if(bp->f1 & SELECT) {
2827                                                 usel[b]++;
2828                                                 vsel[a]++;
2829                                                 sel++;
2830                                         }
2831                                         bp++;
2832                                 }
2833                         }
2834                         if( sel == (nu->pntsu*nu->pntsv) ) {    /* subdivide entire nurb */
2835                    /* Global subdivision is a special case of partial
2836                           subdivision. Strange it is considered separately... */
2837
2838                                 /* count of nodes (after subdivision) along U axis */
2839                                 int countu= nu->pntsu + (nu->pntsu - 1) * number_cuts;
2840