Blender V2.61 - r43446

editcurve.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <math.h>
00034 #include <string.h>
00035 
00036 #ifndef WIN32
00037 #include <unistd.h>
00038 #else
00039 #include <io.h>
00040 #endif
00041 #include <stdlib.h>
00042 
00043 #include "DNA_key_types.h"
00044 #include "DNA_object_types.h"
00045 #include "DNA_scene_types.h"
00046 #include "DNA_anim_types.h"
00047 
00048 #include "MEM_guardedalloc.h"
00049 
00050 #include "BLI_blenlib.h"
00051 #include "BLI_math.h"
00052 #include "BLI_dynstr.h"
00053 #include "BLI_rand.h"
00054 #include "BLI_utildefines.h"
00055 #include "BLI_ghash.h"
00056 
00057 #include "BKE_context.h"
00058 #include "BKE_curve.h"
00059 #include "BKE_depsgraph.h"
00060 #include "BKE_fcurve.h"
00061 #include "BKE_global.h"
00062 #include "BKE_key.h"
00063 #include "BKE_library.h"
00064 #include "BKE_main.h"
00065 #include "BKE_report.h"
00066 #include "BKE_animsys.h"
00067 #include "BKE_action.h"
00068 
00069 #include "WM_api.h"
00070 #include "WM_types.h"
00071 
00072 #include "ED_keyframes_edit.h"
00073 #include "ED_object.h"
00074 #include "ED_screen.h"
00075 #include "ED_transform.h"
00076 #include "ED_types.h"
00077 #include "ED_util.h"
00078 #include "ED_view3d.h"
00079 #include "ED_curve.h"
00080 
00081 #include "curve_intern.h"
00082 
00083 #include "UI_interface.h"
00084 #include "UI_resources.h"
00085 
00086 #include "RNA_access.h"
00087 #include "RNA_define.h"
00088 #include "RNA_enum_types.h"
00089 
00090 /* Undo stuff */
00091 typedef struct {
00092     ListBase nubase;
00093     void *lastsel;
00094     GHash *undoIndex;
00095     ListBase fcurves, drivers;
00096     int actnu;
00097 } UndoCurve;
00098 
00099 /* Definitions needed for shape keys */
00100 typedef struct {
00101     void *orig_cv;
00102     int key_index, nu_index, pt_index;
00103     int switched;
00104     Nurb *orig_nu;
00105 } CVKeyIndex;
00106 
00107 void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus);
00108 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus);
00109 
00110 /* still need to eradicate a few :( */
00111 #define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
00112 
00113 static float nurbcircle[8][2]= {
00114     {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0,  1.0},
00115     {0.0,  1.0}, { 1.0,  1.0}, { 1.0, 0.0}, { 1.0, -1.0}
00116 };
00117 
00118 ListBase *object_editcurve_get(Object *ob)
00119 {
00120     if(ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
00121         Curve *cu= ob->data;
00122         return &cu->editnurb->nurbs;
00123     }
00124     return NULL;
00125 }
00126 
00127 /* this replaces the active flag used in uv/face mode */
00128 static void set_actNurb(Object *obedit, Nurb *nu)
00129 {
00130     Curve *cu= obedit->data;
00131     
00132     if(nu==NULL)
00133         cu->actnu = -1;
00134     else {
00135         ListBase *nurbs= curve_editnurbs(cu);
00136         cu->actnu = BLI_findindex(nurbs, nu);
00137     }
00138 }
00139 
00140 static Nurb *get_actNurb(Object *obedit)
00141 {
00142     Curve *cu= obedit->data;
00143     ListBase *nurbs= curve_editnurbs(cu);
00144 
00145     return BLI_findlink(nurbs, cu->actnu);
00146 }
00147 
00148 /* ******************* SELECTION FUNCTIONS ********************* */
00149 
00150 #define HIDDEN          1
00151 #define VISIBLE         0
00152 
00153 #define FIRST           1
00154 #define LAST            0
00155 
00156 
00157 /* returns 1 in case (de)selection was successful */
00158 static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden)
00159 {   
00160     if(bezt) {
00161         if((bezt->hide==0) || (hidden==1)) {
00162             if(selstatus==1) { /* selects */            
00163                 bezt->f1 |= flag;
00164                 bezt->f2 |= flag;
00165                 bezt->f3 |= flag;
00166                 return 1;           
00167             }
00168             else { /* deselects */  
00169                 bezt->f1 &= ~flag; 
00170                 bezt->f2 &= ~flag; 
00171                 bezt->f3 &= ~flag; 
00172                 return 1;
00173             }
00174         }
00175     }
00176     
00177     return 0;
00178 }
00179 
00180 /* returns 1 in case (de)selection was successful */
00181 static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden) 
00182 {   
00183     if(bp) {
00184         if((bp->hide==0) || (hidden==1)) {
00185             if(selstatus==1) {
00186                 bp->f1 |= flag;
00187                 return 1;
00188             }
00189             else {
00190                 bp->f1 &= ~flag;
00191                 return 1;
00192             }
00193         }
00194     }
00195 
00196     return 0;
00197 }
00198 
00199 static short swap_selection_beztriple(BezTriple *bezt)
00200 {
00201     if(bezt->f2 & SELECT)
00202         return select_beztriple(bezt, DESELECT, 1, VISIBLE);
00203     else
00204         return select_beztriple(bezt, SELECT, 1, VISIBLE);
00205 }
00206 
00207 static short swap_selection_bpoint(BPoint *bp)
00208 {
00209     if(bp->f1 & SELECT)
00210         return select_bpoint(bp, DESELECT, 1, VISIBLE);
00211     else
00212         return select_bpoint(bp, SELECT, 1, VISIBLE);
00213 }
00214 
00215 int isNurbsel(Nurb *nu)
00216 {
00217     BezTriple *bezt;
00218     BPoint *bp;
00219     int a;
00220 
00221     if(nu->type == CU_BEZIER) {
00222         bezt= nu->bezt;
00223         a= nu->pntsu;
00224         while(a--) {
00225             if( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) return 1;
00226             bezt++;
00227         }
00228     }
00229     else {
00230         bp= nu->bp;
00231         a= nu->pntsu*nu->pntsv;
00232         while(a--) {
00233             if( (bp->f1 & SELECT) ) return 1;
00234             bp++;
00235         }
00236     }
00237     return 0;
00238 }
00239 
00240 static int isNurbsel_count(Curve *cu, Nurb *nu)
00241 {
00242     BezTriple *bezt;
00243     BPoint *bp;
00244     int a, sel=0;
00245 
00246     if(nu->type == CU_BEZIER) {
00247         bezt= nu->bezt;
00248         a= nu->pntsu;
00249         while(a--) {
00250             if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) sel++;
00251             bezt++;
00252         }
00253     }
00254     else {
00255         bp= nu->bp;
00256         a= nu->pntsu*nu->pntsv;
00257         while(a--) {
00258             if( (bp->f1 & SELECT) ) sel++;
00259             bp++;
00260         }
00261     }
00262     return sel;
00263 }
00264 
00265 /* ******************* PRINTS ********************* */
00266 
00267 void printknots(Object *obedit)
00268 {
00269     ListBase *editnurb= object_editcurve_get(obedit);
00270     Nurb *nu;
00271     int a, num;
00272 
00273     for(nu= editnurb->first; nu; nu= nu->next) {
00274         if(isNurbsel(nu) &&  nu->type == CU_NURBS) {
00275             if(nu->knotsu) {
00276                 num= KNOTSU(nu);
00277                 for(a=0;a<num;a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
00278             }
00279             if(nu->knotsv) {
00280                 num= KNOTSV(nu);
00281                 for(a=0;a<num;a++) printf("knotv %d: %f\n", a, nu->knotsv[a]);
00282             }
00283         }
00284     }
00285 }
00286 
00287 /* ********************* Shape keys *************** */
00288 
00289 static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, Nurb *orig_nu)
00290 {
00291     CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), "init_cvKeyIndex");
00292 
00293     cvIndex->orig_cv= cv;
00294     cvIndex->key_index= key_index;
00295     cvIndex->nu_index= nu_index;
00296     cvIndex->pt_index= pt_index;
00297     cvIndex->switched= 0;
00298     cvIndex->orig_nu= orig_nu;
00299 
00300     return cvIndex;
00301 }
00302 
00303 static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
00304 {
00305     Nurb *nu= editnurb->nurbs.first;
00306     Nurb *orignu= origBase->first;
00307     GHash *gh;
00308     BezTriple *bezt, *origbezt;
00309     BPoint *bp, *origbp;
00310     CVKeyIndex *keyIndex;
00311     int a, key_index= 0, nu_index= 0, pt_index= 0;
00312 
00313     if(editnurb->keyindex) return;
00314 
00315     gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "editNurb keyIndex");
00316 
00317     while (orignu) {
00318         if (orignu->bezt) {
00319             a= orignu->pntsu;
00320             bezt= nu->bezt;
00321             origbezt= orignu->bezt;
00322             pt_index= 0;
00323             while (a--) {
00324                 keyIndex= init_cvKeyIndex(origbezt, key_index, nu_index, pt_index, orignu);
00325                 BLI_ghash_insert(gh, bezt, keyIndex);
00326                 key_index+= 12;
00327                 bezt++;
00328                 origbezt++;
00329                 pt_index++;
00330             }
00331         } else {
00332             a= orignu->pntsu * orignu->pntsv;
00333             bp= nu->bp;
00334             origbp= orignu->bp;
00335             pt_index= 0;
00336             while (a--) {
00337                 keyIndex= init_cvKeyIndex(origbp, key_index, nu_index, pt_index, orignu);
00338                 BLI_ghash_insert(gh, bp, keyIndex);
00339                 key_index+= 4;
00340                 bp++;
00341                 origbp++;
00342                 pt_index++;
00343             }
00344         }
00345 
00346         nu= nu->next;
00347         orignu= orignu->next;
00348         nu_index++;
00349     }
00350 
00351     editnurb->keyindex= gh;
00352 }
00353 
00354 static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, void *cv)
00355 {
00356     return BLI_ghash_lookup(editnurb->keyindex, cv);
00357 }
00358 
00359 static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, BezTriple *bezt)
00360 {
00361     CVKeyIndex *index= getCVKeyIndex(editnurb, bezt);
00362 
00363     if (!index) {
00364         return NULL;
00365     }
00366 
00367     return (BezTriple*)index->orig_cv;
00368 }
00369 
00370 static BPoint *getKeyIndexOrig_bp(EditNurb *editnurb, BPoint *bp)
00371 {
00372     CVKeyIndex *index= getCVKeyIndex(editnurb, bp);
00373 
00374     if (!index) {
00375         return NULL;
00376     }
00377 
00378     return (BPoint*)index->orig_cv;
00379 }
00380 
00381 static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
00382 {
00383     CVKeyIndex *index= getCVKeyIndex(editnurb, cv);
00384 
00385     if (!index) {
00386         return -1;
00387     }
00388 
00389     return index->key_index;
00390 }
00391 
00392 static void keyIndex_delCV(EditNurb *editnurb, void *cv)
00393 {
00394     if (!editnurb->keyindex) {
00395         return;
00396     }
00397 
00398     BLI_ghash_remove(editnurb->keyindex, cv, NULL, (GHashValFreeFP)MEM_freeN);
00399 }
00400 
00401 static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
00402 {
00403     keyIndex_delCV(editnurb, bezt);
00404 }
00405 
00406 static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp)
00407 {
00408     keyIndex_delCV(editnurb, bp);
00409 }
00410 
00411 static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
00412 {
00413     int a;
00414 
00415     if (!editnurb->keyindex) {
00416         return;
00417     }
00418 
00419     if (nu->bezt) {
00420         BezTriple *bezt= nu->bezt;
00421         a= nu->pntsu;
00422 
00423         while (a--) {
00424             BLI_ghash_remove(editnurb->keyindex, bezt, NULL, (GHashValFreeFP)MEM_freeN);
00425             ++bezt;
00426         }
00427     } else {
00428         BPoint *bp= nu->bp;
00429         a= nu->pntsu * nu->pntsv;
00430 
00431         while (a--) {
00432             BLI_ghash_remove(editnurb->keyindex, bp, NULL, (GHashValFreeFP)MEM_freeN);
00433             ++bp;
00434         }
00435     }
00436 }
00437 
00438 static void keyIndex_delNurbList(EditNurb *editnurb, ListBase *nubase)
00439 {
00440     Nurb *nu= nubase->first;
00441 
00442     while (nu) {
00443         keyIndex_delNurb(editnurb, nu);
00444 
00445         nu= nu->next;
00446     }
00447 }
00448 
00449 static void keyIndex_updateCV(EditNurb *editnurb, char *cv,
00450     char *newcv, int count, int size)
00451 {
00452     int i;
00453     CVKeyIndex *index;
00454 
00455     if (editnurb->keyindex == NULL) {
00456         /* No shape keys - updating not needed */
00457         return;
00458     }
00459 
00460     for (i = 0; i < count; i++) {
00461         index= getCVKeyIndex(editnurb, cv);
00462 
00463         BLI_ghash_remove(editnurb->keyindex, cv, NULL, NULL);
00464 
00465         if (index) {
00466             BLI_ghash_insert(editnurb->keyindex, newcv, index);
00467         }
00468 
00469         newcv += size;
00470         cv += size;
00471     }
00472 }
00473 
00474 static void keyIndex_updateBezt(EditNurb *editnurb, BezTriple *bezt,
00475     BezTriple *newbezt, int count)
00476 {
00477     keyIndex_updateCV(editnurb, (char*)bezt, (char*)newbezt, count, sizeof(BezTriple));
00478 }
00479 
00480 static void keyIndex_updateBP(EditNurb *editnurb, BPoint *bp,
00481     BPoint *newbp, int count)
00482 {
00483     keyIndex_updateCV(editnurb, (char*)bp, (char*)newbp, count, sizeof(BPoint));
00484 }
00485 
00486 static void keyIndex_updateNurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
00487 {
00488     if (nu->bezt) {
00489         keyIndex_updateBezt(editnurb, nu->bezt, newnu->bezt, newnu->pntsu);
00490     } else {
00491         keyIndex_updateBP(editnurb, nu->bp, newnu->bp, newnu->pntsu * newnu->pntsv);
00492     }
00493 }
00494 
00495 static void keyIndex_swap(EditNurb *editnurb, void *a, void *b)
00496 {
00497     CVKeyIndex *index1= getCVKeyIndex(editnurb, a);
00498     CVKeyIndex *index2= getCVKeyIndex(editnurb, b);
00499 
00500     BLI_ghash_remove(editnurb->keyindex, a, NULL, NULL);
00501     BLI_ghash_remove(editnurb->keyindex, b, NULL, NULL);
00502 
00503     if(index2) BLI_ghash_insert(editnurb->keyindex, a, index2);
00504     if(index1) BLI_ghash_insert(editnurb->keyindex, b, index1);
00505 }
00506 
00507 static void keyIndex_switchDirection(EditNurb *editnurb, Nurb *nu)
00508 {
00509     int a;
00510     CVKeyIndex *index1, *index2;
00511 
00512     if (nu->bezt) {
00513         BezTriple *bezt1, *bezt2;
00514 
00515         a= nu->pntsu;
00516 
00517         bezt1= nu->bezt;
00518         bezt2= bezt1+(a-1);
00519 
00520         if (a & 1) ++a;
00521 
00522         a/=2;
00523 
00524         while (a--) {
00525             index1= getCVKeyIndex(editnurb, bezt1);
00526             index2= getCVKeyIndex(editnurb, bezt2);
00527 
00528             if(index1) index1->switched= !index1->switched;
00529 
00530             if (bezt1 != bezt2) {
00531                 keyIndex_swap(editnurb, bezt1, bezt2);
00532 
00533                 if(index2) index2->switched= !index2->switched;
00534             }
00535 
00536             bezt1++;
00537             bezt2--;
00538         }
00539     } else {
00540         BPoint *bp1, *bp2;
00541 
00542         if (nu->pntsv == 1) {
00543             a= nu->pntsu;
00544             bp1= nu->bp;
00545             bp2= bp1+(a-1);
00546             a/= 2;
00547             while(bp1!=bp2 && a>0) {
00548                 index1= getCVKeyIndex(editnurb, bp1);
00549                 index2= getCVKeyIndex(editnurb, bp2);
00550 
00551                 if(index1) index1->switched= !index1->switched;
00552 
00553                 if (bp1 != bp2) {
00554                     if(index2) index2->switched= !index2->switched;
00555 
00556                     keyIndex_swap(editnurb, bp1, bp2);
00557                 }
00558 
00559                 a--;
00560                 bp1++;
00561                 bp2--;
00562             }
00563         } else {
00564             int b;
00565 
00566             for(b=0; b<nu->pntsv; b++) {
00567 
00568                 bp1= nu->bp+b*nu->pntsu;
00569                 a= nu->pntsu;
00570                 bp2= bp1+(a-1);
00571                 a/= 2;
00572 
00573                 while(bp1!=bp2 && a>0) {
00574                     index1= getCVKeyIndex(editnurb, bp1);
00575                     index2= getCVKeyIndex(editnurb, bp2);
00576 
00577                     if(index1) index1->switched= !index1->switched;
00578 
00579                     if (bp1 != bp2) {
00580                         if(index2) index2->switched= !index2->switched;
00581 
00582                         keyIndex_swap(editnurb, bp1, bp2);
00583                     }
00584 
00585                     a--;
00586                     bp1++;
00587                     bp2--;
00588                 }
00589             }
00590 
00591         }
00592     }
00593 }
00594 
00595 static void switch_keys_direction(Curve *cu, Nurb *actnu)
00596 {
00597     KeyBlock *currkey;
00598     EditNurb *editnurb= cu->editnurb;
00599     ListBase *nubase= &editnurb->nurbs;
00600     Nurb *nu;
00601     float *fp;
00602     int a;
00603 
00604     currkey = cu->key->block.first;
00605     while(currkey) {
00606         fp= currkey->data;
00607 
00608         nu= nubase->first;
00609         while (nu) {
00610             if (nu->bezt) {
00611                 BezTriple *bezt= nu->bezt;
00612                 a= nu->pntsu;
00613                 if (nu == actnu) {
00614                     while (a--) {
00615                         if(getKeyIndexOrig_bezt(editnurb, bezt)) {
00616                             swap_v3_v3(fp, fp + 6);
00617                             *(fp+9) = -*(fp+9);
00618                             fp += 12;
00619                         }
00620                         bezt++;
00621                     }
00622                 } else fp += a * 12;
00623             } else {
00624                 BPoint *bp= nu->bp;
00625                 a= nu->pntsu * nu->pntsv;
00626                 if (nu == actnu) {
00627                     while (a--) {
00628                         if(getKeyIndexOrig_bp(editnurb, bp)) {
00629                             *(fp+3) = -*(fp+3);
00630                             fp += 4;
00631                         }
00632                         bp++;
00633                     }
00634                 } else fp += a * 4;
00635             }
00636 
00637             nu= nu->next;
00638         }
00639 
00640         currkey= currkey->next;
00641     }
00642 }
00643 
00644 static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu)
00645 {
00646     EditNurb *editnurb= cu->editnurb;
00647 
00648     if (!editnurb->keyindex) {
00649         /* no shape keys - nothing to do */
00650         return;
00651     }
00652 
00653     keyIndex_switchDirection(editnurb, nu);
00654     if(cu->key)
00655         switch_keys_direction(cu, nu);
00656 }
00657 
00658 static GHash *dupli_keyIndexHash(GHash *keyindex)
00659 {
00660     GHash *gh;
00661     GHashIterator *hashIter;
00662 
00663     gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "dupli_keyIndex gh");
00664 
00665     for(hashIter = BLI_ghashIterator_new(keyindex);
00666                    !BLI_ghashIterator_isDone(hashIter);
00667                    BLI_ghashIterator_step(hashIter)) {
00668         void *cv = BLI_ghashIterator_getKey(hashIter);
00669         CVKeyIndex *index = BLI_ghashIterator_getValue(hashIter);
00670         CVKeyIndex *newIndex = MEM_callocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
00671 
00672         memcpy(newIndex, index, sizeof(CVKeyIndex));
00673 
00674         BLI_ghash_insert(gh, cv, newIndex);
00675     }
00676 
00677     BLI_ghashIterator_free(hashIter);
00678 
00679     return gh;
00680 }
00681 
00682 static void key_to_bezt(float *key, BezTriple *basebezt, BezTriple *bezt)
00683 {
00684     memcpy(bezt, basebezt, sizeof(BezTriple));
00685     memcpy(bezt->vec, key, sizeof(float) * 9);
00686     bezt->alfa= key[9];
00687 }
00688 
00689 static void bezt_to_key(BezTriple *bezt, float *key)
00690 {
00691     memcpy(key, bezt->vec, sizeof(float) * 9);
00692     key[9] = bezt->alfa;
00693 }
00694 
00695 static void calc_keyHandles(ListBase *nurb, float *key)
00696 {
00697     Nurb *nu;
00698     int a;
00699     float *fp= key;
00700     BezTriple *bezt;
00701 
00702     nu= nurb->first;
00703     while (nu) {
00704         if (nu->bezt) {
00705             BezTriple *prevp, *nextp;
00706             BezTriple cur, prev, next;
00707             float *startfp, *prevfp, *nextfp;
00708 
00709             bezt= nu->bezt;
00710             a= nu->pntsu;
00711             startfp= fp;
00712 
00713             if(nu->flagu & CU_NURB_CYCLIC) {
00714                 prevp= bezt+(a-1);
00715                 prevfp= fp+(12 * (a-1));
00716             } else {
00717                 prevp= NULL;
00718                 prevfp= NULL;
00719             }
00720 
00721             nextp= bezt + 1;
00722             nextfp= fp + 12;
00723 
00724             while (a--) {
00725                 key_to_bezt(fp, bezt, &cur);
00726 
00727                 if (nextp) key_to_bezt(nextfp, nextp, &next);
00728                 if (prevp) key_to_bezt(prevfp, prevp, &prev);
00729 
00730                 calchandleNurb(&cur, prevp ? &prev : NULL, nextp ? &next : NULL, 0);
00731                 bezt_to_key(&cur, fp);
00732 
00733                 prevp= bezt;
00734                 prevfp= fp;
00735                 if(a==1) {
00736                     if(nu->flagu & CU_NURB_CYCLIC) {
00737                         nextp= nu->bezt;
00738                         nextfp= startfp;
00739                     } else {
00740                         nextp= NULL;
00741                         nextfp= NULL;
00742                     }
00743                 }
00744                 else {
00745                     ++nextp;
00746                     nextfp += 12;
00747                 }
00748 
00749                 ++bezt;
00750                 fp += 12;
00751             }
00752         } else {
00753             a= nu->pntsu * nu->pntsv;
00754             fp += a * 4;
00755         }
00756 
00757         nu= nu->next;
00758     }
00759 }
00760 
00761 static void calc_shapeKeys(Object *obedit)
00762 {
00763     Curve *cu= (Curve*)obedit->data;
00764 
00765     /* are there keys? */
00766     if(cu->key) {
00767         int a, i;
00768         EditNurb *editnurb= cu->editnurb;
00769         KeyBlock *currkey;
00770         KeyBlock *actkey= BLI_findlink(&cu->key->block, editnurb->shapenr-1);
00771         BezTriple *bezt, *oldbezt;
00772         BPoint *bp, *oldbp;
00773         Nurb *nu;
00774         int totvert= count_curveverts(&editnurb->nurbs);
00775 
00776         float (*ofs)[3] = NULL;
00777         float *oldkey, *newkey, *ofp;
00778 
00779         /* editing the base key should update others */
00780         if(cu->key->type==KEY_RELATIVE) {
00781             int act_is_basis = 0;
00782             /* find if this key is a basis for any others */
00783             for(currkey = cu->key->block.first; currkey; currkey= currkey->next) {
00784                 if(editnurb->shapenr-1 == currkey->relative) {
00785                     act_is_basis = 1;
00786                     break;
00787                 }
00788             }
00789 
00790             if(act_is_basis) { /* active key is a base */
00791                 int totvec= 0;
00792 
00793                 /* Calculate needed memory to store offset */
00794                 nu= editnurb->nurbs.first;
00795                 while(nu) {
00796                     if (nu->bezt) {
00797                         /* Three vects to store handles and one for alfa */
00798                         totvec+= nu->pntsu * 4;
00799                     } else {
00800                         totvec+= 2 * nu->pntsu * nu->pntsv;
00801                     }
00802 
00803                     nu= nu->next;
00804                 }
00805 
00806                 ofs= MEM_callocN(sizeof(float) * 3 * totvec,  "currkey->data");
00807                 nu= editnurb->nurbs.first;
00808                 i= 0;
00809                 while(nu) {
00810                     if(nu->bezt) {
00811                         bezt= nu->bezt;
00812                         a= nu->pntsu;
00813                         while(a--) {
00814                             oldbezt= getKeyIndexOrig_bezt(editnurb, bezt);
00815 
00816                             if (oldbezt) {
00817                                 int j;
00818                                 for (j= 0; j < 3; ++j) {
00819                                     sub_v3_v3v3(ofs[i], bezt->vec[j], oldbezt->vec[j]);
00820                                     i++;
00821                                 }
00822                                 ofs[i++][0]= bezt->alfa - oldbezt->alfa;
00823                             } else {
00824                                 i += 4;
00825                             }
00826                             bezt++;
00827                         }
00828                     }
00829                     else {
00830                         bp= nu->bp;
00831                         a= nu->pntsu*nu->pntsv;
00832                         while(a--) {
00833                             oldbp= getKeyIndexOrig_bp(editnurb, bp);
00834                             if (oldbp) {
00835                                 sub_v3_v3v3(ofs[i], bp->vec, oldbp->vec);
00836                                 ofs[i+1][0]= bp->alfa - oldbp->alfa;
00837                             }
00838                             i += 2;
00839                             ++bp;
00840                         }
00841                     }
00842 
00843                     nu= nu->next;
00844                 }
00845             }
00846         }
00847 
00848         currkey = cu->key->block.first;
00849         while(currkey) {
00850             int apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr-1 == currkey->relative));
00851 
00852             float *fp= newkey= MEM_callocN(cu->key->elemsize * totvert,  "currkey->data");
00853             ofp= oldkey = currkey->data;
00854 
00855             nu= editnurb->nurbs.first;
00856             i = 0;
00857             while(nu) {
00858                 if(currkey == actkey) {
00859                     int restore= actkey != cu->key->refkey;
00860 
00861                     if(nu->bezt) {
00862                         bezt= nu->bezt;
00863                         a= nu->pntsu;
00864                         while(a--) {
00865                             int j;
00866                             oldbezt= getKeyIndexOrig_bezt(editnurb, bezt);
00867 
00868                             for (j= 0; j < 3; ++j, ++i) {
00869                                 copy_v3_v3(fp, bezt->vec[j]);
00870 
00871                                 if (restore && oldbezt) {
00872                                     copy_v3_v3(bezt->vec[j], oldbezt->vec[j]);
00873                                 }
00874 
00875                                 fp+= 3;
00876                             }
00877                             fp[0]= bezt->alfa;
00878 
00879                             if(restore && oldbezt) {
00880                                 bezt->alfa= oldbezt->alfa;
00881                             }
00882 
00883                             fp+= 3; ++i;/* alphas */
00884                             ++bezt;
00885                         }
00886                     }
00887                     else {
00888                         bp= nu->bp;
00889                         a= nu->pntsu*nu->pntsv;
00890                         while(a--) {
00891                             oldbp= getKeyIndexOrig_bp(editnurb, bp);
00892 
00893                             copy_v3_v3(fp, bp->vec);
00894 
00895                             fp[3]= bp->alfa;
00896 
00897                             if(restore && oldbp) {
00898                                 copy_v3_v3(bp->vec, oldbp->vec);
00899                                 bp->alfa= oldbp->alfa;
00900                             }
00901 
00902                             fp+= 4;
00903                             ++bp;
00904                             i+=2;
00905                         }
00906                     }
00907                 }
00908                 else {
00909                     int index;
00910                     float *curofp;
00911 
00912                     if(oldkey) {
00913                         if(nu->bezt) {
00914                             bezt= nu->bezt;
00915                             a= nu->pntsu;
00916 
00917                             while(a--) {
00918                                 index= getKeyIndexOrig_keyIndex(editnurb, bezt);
00919                                 if (index >= 0) {
00920                                     int j;
00921                                     curofp= ofp + index;
00922 
00923                                     for (j= 0; j < 3; ++j, ++i) {
00924                                         copy_v3_v3(fp, curofp);
00925 
00926                                         if(apply_offset) {
00927                                             add_v3_v3(fp, ofs[i]);
00928                                         }
00929 
00930                                         fp+= 3; curofp+= 3;
00931                                     }
00932                                     fp[0]= curofp[0];
00933 
00934                                     if(apply_offset) {
00935                                         /* apply alfa offsets */
00936                                         add_v3_v3(fp, ofs[i]);
00937                                         ++i;
00938                                     }
00939 
00940                                     fp+= 3; /* alphas */
00941                                 } else {
00942                                     int j;
00943                                     for (j= 0; j < 3; ++j, ++i) {
00944                                         copy_v3_v3(fp, bezt->vec[j]);
00945                                         fp+= 3;
00946                                     }
00947                                     fp[0]= bezt->alfa;
00948 
00949                                     fp+= 3; /* alphas */
00950                                 }
00951                                 ++bezt;
00952                             }
00953                         }
00954                         else {
00955                             bp= nu->bp;
00956                             a= nu->pntsu*nu->pntsv;
00957                             while(a--) {
00958                                 index= getKeyIndexOrig_keyIndex(editnurb, bp);
00959 
00960                                 if (index >= 0) {
00961                                     curofp= ofp + index;
00962                                     copy_v3_v3(fp, curofp);
00963                                     fp[3]= curofp[3];
00964 
00965                                     if(apply_offset) {
00966                                         add_v3_v3(fp, ofs[i]);
00967                                         fp[3]+=ofs[i+1][0];
00968                                     }
00969                                 } else {
00970                                     copy_v3_v3(fp, bp->vec);
00971                                     fp[3]= bp->alfa;
00972                                 }
00973 
00974                                 fp+= 4;
00975                                 ++bp;
00976                                 i+=2;
00977                             }
00978                         }
00979                     }
00980                 }
00981 
00982                 nu= nu->next;
00983             }
00984 
00985             if (apply_offset) {
00986                 /* handles could become malicious after offsets applying */
00987                 calc_keyHandles(&editnurb->nurbs, newkey);
00988             }
00989 
00990             currkey->totelem= totvert;
00991             if(currkey->data) MEM_freeN(currkey->data);
00992             currkey->data = newkey;
00993 
00994             currkey= currkey->next;
00995         }
00996 
00997         if(ofs) MEM_freeN(ofs);
00998     }
00999 }
01000 
01001 /* ********************* Amimation data *************** */
01002 
01003 static int curve_is_animated(Object *ob)
01004 {
01005     Curve *cu= (Curve*)ob->data;
01006     AnimData *ad= BKE_animdata_from_id(&cu->id);
01007 
01008     return ad && (ad->action || ad->drivers.first);
01009 }
01010 
01011 static void fcurve_path_rename(AnimData *ad, char *orig_rna_path, char *rna_path, ListBase *orig_curves, ListBase *curves)
01012 {
01013     FCurve *fcu, *nfcu, *nextfcu;
01014     int len= strlen(orig_rna_path);
01015 
01016     fcu= orig_curves->first;
01017     while (fcu) {
01018         nextfcu= fcu->next;
01019         if(!strncmp(fcu->rna_path, orig_rna_path, len)) {
01020             char *spath, *suffix= fcu->rna_path + len;
01021             nfcu= copy_fcurve(fcu);
01022             spath= nfcu->rna_path;
01023             nfcu->rna_path= BLI_sprintfN("%s%s", rna_path, suffix);
01024             BLI_addtail(curves, nfcu);
01025 
01026             if (fcu->grp) {
01027                 action_groups_remove_channel(ad->action, fcu);
01028                 action_groups_add_channel(ad->action, fcu->grp, nfcu);
01029             }
01030             else if (ad->action && &ad->action->curves == orig_curves)
01031                 BLI_remlink(&ad->action->curves, fcu);
01032             else
01033                 BLI_remlink(&ad->drivers, fcu);
01034 
01035             free_fcurve(fcu);
01036 
01037             MEM_freeN(spath);
01038         }
01039         fcu= nextfcu;
01040     }
01041 }
01042 
01043 static void fcurve_remove(AnimData *ad, ListBase *orig_curves, FCurve *fcu)
01044 {
01045     if(orig_curves==&ad->drivers) BLI_remlink(&ad->drivers, fcu);
01046     else action_groups_remove_channel(ad->action, fcu);
01047 
01048     free_fcurve(fcu);
01049 }
01050 
01051 static void curve_rename_fcurves(Object *obedit, ListBase *orig_curves)
01052 {
01053     int nu_index= 0, a, pt_index;
01054     Curve *cu= (Curve*)obedit->data;
01055     EditNurb *editnurb= cu->editnurb;
01056     Nurb *nu= editnurb->nurbs.first;
01057     CVKeyIndex *keyIndex;
01058     char rna_path[64], orig_rna_path[64];
01059     AnimData *ad= BKE_animdata_from_id(&cu->id);
01060     ListBase curves= {NULL, NULL};
01061     FCurve *fcu, *next;
01062 
01063     while(nu) {
01064         if(nu->bezt) {
01065             BezTriple *bezt= nu->bezt;
01066             a= nu->pntsu;
01067             pt_index= 0;
01068 
01069             while (a--) {
01070                 keyIndex= getCVKeyIndex(editnurb, bezt);
01071                 if(keyIndex) {
01072                     BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d].bezier_points[%d]", nu_index, pt_index);
01073                     BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d].bezier_points[%d]", keyIndex->nu_index, keyIndex->pt_index);
01074 
01075                     if(keyIndex->switched) {
01076                         char handle_path[64], orig_handle_path[64];
01077                         BLI_snprintf(orig_handle_path, sizeof(orig_rna_path), "%s.handle_left", orig_rna_path);
01078                         BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_right", rna_path);
01079                         fcurve_path_rename(ad, orig_handle_path, handle_path, orig_curves, &curves);
01080 
01081                         BLI_snprintf(orig_handle_path, sizeof(orig_rna_path), "%s.handle_right", orig_rna_path);
01082                         BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_left", rna_path);
01083                         fcurve_path_rename(ad, orig_handle_path, handle_path, orig_curves, &curves);
01084                     }
01085 
01086                     fcurve_path_rename(ad, orig_rna_path, rna_path, orig_curves, &curves);
01087 
01088                     keyIndex->nu_index= nu_index;
01089                     keyIndex->pt_index= pt_index;
01090                 }
01091 
01092                 bezt++;
01093                 pt_index++;
01094             }
01095         } else {
01096             BPoint *bp= nu->bp;
01097             a= nu->pntsu * nu->pntsv;
01098             pt_index= 0;
01099 
01100             while (a--) {
01101                 keyIndex= getCVKeyIndex(editnurb, bp);
01102                 if(keyIndex) {
01103                     BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d].points[%d]", nu_index, pt_index);
01104                     BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d].points[%d]", keyIndex->nu_index, keyIndex->pt_index);
01105                     fcurve_path_rename(ad, orig_rna_path, rna_path, orig_curves, &curves);
01106 
01107                     keyIndex->nu_index= nu_index;
01108                     keyIndex->pt_index= pt_index;
01109                 }
01110 
01111                 bp++;
01112                 pt_index++;
01113             }
01114         }
01115         nu= nu->next;
01116         nu_index++;
01117     }
01118 
01119     /* remove pathes for removed control points
01120        need this to make further step with copying non-cv related curves copying
01121        not touching cv's f-cruves */
01122     for(fcu= orig_curves->first; fcu; fcu= next) {
01123         next= fcu->next;
01124 
01125         if(!strncmp(fcu->rna_path, "splines", 7)) {
01126             char *ch= strchr(fcu->rna_path, '.');
01127 
01128             if (ch && (!strncmp(ch, ".bezier_points", 14) || !strncmp(ch, ".points", 7)))
01129                 fcurve_remove(ad, orig_curves, fcu);
01130         }
01131     }
01132 
01133     nu_index= 0;
01134     nu= editnurb->nurbs.first;
01135     while(nu) {
01136         keyIndex= NULL;
01137         if(nu->pntsu) {
01138             if(nu->bezt) keyIndex= getCVKeyIndex(editnurb, &nu->bezt[0]);
01139             else keyIndex= getCVKeyIndex(editnurb, &nu->bp[0]);
01140         }
01141 
01142         if(keyIndex) {
01143             BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d]", nu_index);
01144             BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d]", keyIndex->nu_index);
01145             fcurve_path_rename(ad, orig_rna_path, rna_path, orig_curves, &curves);
01146         }
01147 
01148         nu_index++;
01149         nu= nu->next;
01150     }
01151 
01152     /* the remainders in orig_curves can be copied back (like follow path) */
01153     /* (if it's not path to spline) */
01154     for(fcu= orig_curves->first; fcu; fcu= next) {
01155         next= fcu->next;
01156 
01157         if(!strncmp(fcu->rna_path, "splines", 7)) fcurve_remove(ad, orig_curves, fcu);
01158         else BLI_addtail(&curves, fcu);
01159     }
01160 
01161     *orig_curves= curves;
01162 }
01163 
01164 /* return 0 if animation data wasn't changed, 1 otherwise */
01165 int ED_curve_updateAnimPaths(Object *obedit)
01166 {
01167     Curve *cu= (Curve*)obedit->data;
01168     AnimData *ad= BKE_animdata_from_id(&cu->id);
01169 
01170     if(!curve_is_animated(obedit)) return 0;
01171 
01172     if(ad->action)
01173         curve_rename_fcurves(obedit, &ad->action->curves);
01174 
01175     curve_rename_fcurves(obedit, &ad->drivers);
01176 
01177     return 1;
01178 }
01179 
01180 /* ********************* LOAD and MAKE *************** */
01181 
01182 /* load editNurb in object */
01183 void load_editNurb(Object *obedit)
01184 {
01185     ListBase *editnurb= object_editcurve_get(obedit);
01186 
01187     if(obedit==NULL) return;
01188 
01189     set_actNurb(obedit, NULL);
01190 
01191     if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
01192         Curve *cu= obedit->data;
01193         Nurb *nu, *newnu;
01194         ListBase newnurb= {NULL, NULL}, oldnurb= cu->nurb;
01195 
01196         for(nu= editnurb->first; nu; nu= nu->next) {
01197             newnu= duplicateNurb(nu);
01198             BLI_addtail(&newnurb, newnu);
01199 
01200             if(nu->type == CU_NURBS) {
01201                 clamp_nurb_order_u(nu);
01202             }
01203         }
01204 
01205         cu->nurb= newnurb;
01206 
01207         calc_shapeKeys(obedit);
01208         ED_curve_updateAnimPaths(obedit);
01209 
01210         freeNurblist(&oldnurb);
01211     }
01212 
01213     set_actNurb(obedit, NULL);
01214 }
01215 
01216 /* make copy in cu->editnurb */
01217 void make_editNurb(Object *obedit)
01218 {
01219     Curve *cu= (Curve*)obedit->data;
01220     EditNurb *editnurb= cu->editnurb;
01221     Nurb *nu, *newnu, *nu_act= NULL;
01222     KeyBlock *actkey;
01223 
01224 
01225     set_actNurb(obedit, NULL);
01226 
01227     if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
01228         actkey= ob_get_keyblock(obedit);
01229 
01230         if(actkey) {
01231             // XXX strcpy(G.editModeTitleExtra, "(Key) ");
01232             undo_editmode_clear();
01233             key_to_curve(actkey, cu, &cu->nurb);
01234         }
01235 
01236         if(editnurb) {
01237             freeNurblist(&editnurb->nurbs);
01238             free_curve_editNurb_keyIndex(editnurb);
01239             editnurb->keyindex= NULL;
01240         } else {
01241             editnurb= MEM_callocN(sizeof(EditNurb), "editnurb");
01242             cu->editnurb= editnurb;
01243         }
01244 
01245         nu= cu->nurb.first;
01246         cu->lastsel= NULL;   /* for select row */
01247 
01248         while(nu) {
01249             newnu= duplicateNurb(nu);
01250             test2DNurb(newnu);  // after join, or any other creation of curve
01251             BLI_addtail(&editnurb->nurbs, newnu);
01252 
01253             if (nu_act == NULL && isNurbsel(nu)) {
01254                 nu_act= newnu;
01255                 set_actNurb(obedit, newnu);
01256             }
01257 
01258             nu= nu->next;
01259         }
01260 
01261         if(actkey)
01262             editnurb->shapenr= obedit->shapenr;
01263 
01264         /* animation could be added in editmode even if teher was no animdata i
01265            object mode hence we always need CVs index be created */
01266         init_editNurb_keyIndex(editnurb, &cu->nurb);
01267     }
01268 }
01269 
01270 void free_editNurb(Object *obedit)
01271 {
01272     Curve *cu= obedit->data;
01273 
01274     free_curve_editNurb(cu);
01275 }
01276 
01277 void CU_deselect_all(Object *obedit)
01278 {
01279     ListBase *editnurb= object_editcurve_get(obedit);
01280 
01281     if (editnurb) {
01282         selectend_nurb(obedit, FIRST, 0, DESELECT); /* set first control points as unselected */
01283         select_adjacent_cp(editnurb, 1, 1, DESELECT); /* cascade selection */
01284     }
01285 }
01286 
01287 void CU_select_all(Object *obedit)
01288 {
01289     ListBase *editnurb= object_editcurve_get(obedit);
01290 
01291     if (editnurb) {
01292         selectend_nurb(obedit, FIRST, 0, SELECT); /* set first control points as unselected */
01293         select_adjacent_cp(editnurb, 1, 1, SELECT); /* cascade selection */
01294     }
01295 }
01296 
01297 void CU_select_swap(Object *obedit)
01298 {
01299     ListBase *editnurb= object_editcurve_get(obedit);
01300 
01301     if (editnurb) {
01302         Curve *cu= obedit->data;
01303         Nurb *nu;
01304         BPoint *bp;
01305         BezTriple *bezt;
01306         int a;
01307 
01308         cu->lastsel= NULL;
01309 
01310         for(nu= editnurb->first; nu; nu= nu->next) {
01311             if(nu->type == CU_BEZIER) {
01312                 bezt= nu->bezt;
01313                 a= nu->pntsu;
01314                 while(a--) {
01315                     if(bezt->hide==0) {
01316                         bezt->f2 ^= SELECT; /* always do the center point */
01317                         if((cu->drawflag & CU_HIDE_HANDLES)==0) {
01318                             bezt->f1 ^= SELECT;
01319                             bezt->f3 ^= SELECT;
01320                         }
01321                     }
01322                     bezt++;
01323                 }
01324             }
01325             else {
01326                 bp= nu->bp;
01327                 a= nu->pntsu*nu->pntsv;
01328                 while(a--) {
01329                     swap_selection_bpoint(bp);
01330                     bp++;
01331                 }
01332             }
01333         }
01334     }
01335 }
01336 
01337 /******************** separate operator ***********************/
01338 
01339 static int separate_exec(bContext *C, wmOperator *op)
01340 {
01341     Main *bmain= CTX_data_main(C);
01342     Scene *scene= CTX_data_scene(C);
01343     Nurb *nu, *nu1;
01344     Object *oldob, *newob;
01345     Base *oldbase, *newbase;
01346     Curve *oldcu, *newcu;
01347     EditNurb *oldedit, *newedit;
01348 
01349     oldbase= CTX_data_active_base(C);
01350     oldob= oldbase->object;
01351     oldcu= oldob->data;
01352     oldedit= oldcu->editnurb;
01353 
01354     if(oldcu->key) {
01355         BKE_report(op->reports, RPT_ERROR, "Can't separate a curve with vertex keys");
01356         return OPERATOR_CANCELLED;
01357     }
01358 
01359     WM_cursor_wait(1);
01360     
01361     /* 1. duplicate the object and data */
01362     newbase= ED_object_add_duplicate(bmain, scene, oldbase, 0); /* 0 = fully linked */
01363     ED_base_object_select(newbase, BA_DESELECT);
01364     newob= newbase->object;
01365 
01366     newcu= newob->data= copy_curve(oldcu);
01367     newcu->editnurb= NULL;
01368     oldcu->id.us--; /* because new curve is a copy: reduce user count */
01369 
01370     /* 2. put new object in editmode and clear it */
01371     make_editNurb(newob);
01372     newedit= newcu->editnurb;
01373     freeNurblist(&newedit->nurbs);
01374     free_curve_editNurb_keyIndex(newedit);
01375 
01376     /* 3. move over parts from old object */
01377     for(nu= oldedit->nurbs.first; nu; nu=nu1) {
01378         nu1= nu->next;
01379 
01380         if(isNurbsel(nu)) {
01381             BLI_remlink(&oldedit->nurbs, nu);
01382             BLI_addtail(&newedit->nurbs, nu);
01383         }
01384     }
01385 
01386     /* 4. put old object out of editmode */
01387     load_editNurb(newob);
01388     free_editNurb(newob);
01389 
01390     DAG_id_tag_update(&oldob->id, OB_RECALC_DATA);  /* this is the original one */
01391     DAG_id_tag_update(&newob->id, OB_RECALC_DATA);  /* this is the separated one */
01392 
01393     WM_event_add_notifier(C, NC_GEOM|ND_DATA, oldob->data);
01394 
01395     WM_cursor_wait(0);
01396 
01397     return OPERATOR_FINISHED;
01398 }
01399 
01400 void CURVE_OT_separate(wmOperatorType *ot)
01401 {
01402     /* identifiers */
01403     ot->name= "Separate";
01404     ot->idname= "CURVE_OT_separate";
01405     
01406     /* api callbacks */
01407     ot->exec= separate_exec;
01408     ot->poll= ED_operator_editsurfcurve;
01409     
01410     /* flags */
01411     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01412 }
01413 
01414 /* ******************* FLAGS ********************* */
01415 
01416 static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
01417 {
01418     /* return u!=-1:     1 row in u-direction selected. U has value between 0-pntsv 
01419      * return v!=-1: 1 collumn in v-direction selected. V has value between 0-pntsu 
01420      */
01421     BPoint *bp;
01422     int a, b, sel;
01423 
01424     *u= *v= -1;
01425 
01426     bp= nu->bp;
01427     for(b=0; b<nu->pntsv; b++) {
01428         sel= 0;
01429         for(a=0; a<nu->pntsu; a++, bp++) {
01430             if(bp->f1 & flag) sel++;
01431         }
01432         if(sel==nu->pntsu) {
01433             if(*u== -1) *u= b;
01434             else return 0;
01435         }
01436         else if(sel>1) return 0;    /* because sel==1 is still ok */
01437     }
01438 
01439     for(a=0; a<nu->pntsu; a++) {
01440         sel= 0;
01441         bp= nu->bp+a;
01442         for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
01443             if(bp->f1 & flag) sel++;
01444         }
01445         if(sel==nu->pntsv) {
01446             if(*v== -1) *v= a;
01447             else return 0;
01448         }
01449         else if(sel>1) return 0;
01450     }
01451 
01452     if(*u==-1 && *v>-1) return 1;
01453     if(*v==-1 && *u>-1) return 1;
01454     return 0;
01455 }
01456 
01457 static void setflagsNurb(ListBase *editnurb, short flag)
01458 {
01459     Nurb *nu;
01460     BezTriple *bezt;
01461     BPoint *bp;
01462     int a;
01463 
01464     for(nu= editnurb->first; nu; nu= nu->next) {
01465         if(nu->type == CU_BEZIER) {
01466             a= nu->pntsu;
01467             bezt= nu->bezt;
01468             while(a--) {
01469                 bezt->f1= bezt->f2= bezt->f3= flag;
01470                 bezt++;
01471             }
01472         }
01473         else {
01474             a= nu->pntsu*nu->pntsv;
01475             bp= nu->bp;
01476             while(a--) {
01477                 bp->f1= flag;
01478                 bp++;
01479             }
01480         }
01481     }
01482 }
01483 
01484 static void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float rotmat[][3])
01485 {
01486     /* all verts with (flag & 'flag') rotate */
01487     Nurb *nu;
01488     BPoint *bp;
01489     int a;
01490 
01491     for(nu= editnurb->first; nu; nu= nu->next) {
01492         if(nu->type == CU_NURBS) {
01493             bp= nu->bp;
01494             a= nu->pntsu*nu->pntsv;
01495 
01496             while(a--) {
01497                 if(bp->f1 & flag) {
01498                     sub_v3_v3(bp->vec, cent);
01499                     mul_m3_v3(rotmat, bp->vec);
01500                     add_v3_v3(bp->vec, cent);
01501                 }
01502                 bp++;
01503             }
01504         }
01505     }
01506 }
01507 
01508 static void translateflagNurb(ListBase *editnurb, short flag, float *vec)
01509 {
01510     /* all verts with ('flag' & flag) translate */
01511     Nurb *nu;
01512     BezTriple *bezt;
01513     BPoint *bp;
01514     int a;
01515 
01516     for(nu= editnurb->first; nu; nu= nu->next) {
01517         if(nu->type == CU_BEZIER) {
01518             a= nu->pntsu;
01519             bezt= nu->bezt;
01520             while(a--) {
01521                 if(bezt->f1 & flag) add_v3_v3(bezt->vec[0], vec);
01522                 if(bezt->f2 & flag) add_v3_v3(bezt->vec[1], vec);
01523                 if(bezt->f3 & flag) add_v3_v3(bezt->vec[2], vec);
01524                 bezt++;
01525             }
01526         }
01527         else {
01528             a= nu->pntsu*nu->pntsv;
01529             bp= nu->bp;
01530             while(a--) {
01531                 if(bp->f1 & flag) add_v3_v3(bp->vec, vec);
01532                 bp++;
01533             }
01534         }
01535 
01536         test2DNurb(nu);
01537     }
01538 }
01539 
01540 static void weightflagNurb(ListBase *editnurb, short flag, float w)
01541 {
01542     Nurb *nu;
01543     BPoint *bp;
01544     int a;
01545 
01546     for(nu= editnurb->first; nu; nu= nu->next) {
01547         if(nu->type == CU_NURBS) {
01548             a= nu->pntsu*nu->pntsv;
01549             bp= nu->bp;
01550             while(a--) {
01551                 if(bp->f1 & flag) {
01552                     /* a mode used to exist for replace/multiple but is was unused */
01553                     bp->vec[3]*= w;
01554                 }
01555                 bp++;
01556             }
01557         }
01558     }
01559 }
01560 
01561 static int deleteflagNurb(bContext *C, wmOperator *UNUSED(op), int flag)
01562 {
01563     Object *obedit= CTX_data_edit_object(C);
01564     Curve *cu= obedit->data;
01565     ListBase *editnurb= object_editcurve_get(obedit);
01566     Nurb *nu, *next;
01567     BPoint *bp, *bpn, *newbp;
01568     int a, b, newu, newv, sel;
01569 
01570     if(obedit->type==OB_SURF);
01571     else return OPERATOR_CANCELLED;
01572 
01573     cu->lastsel= NULL;
01574 
01575     nu= editnurb->first;
01576     while(nu) {
01577         next= nu->next;
01578 
01579         /* is entire nurb selected */
01580         bp= nu->bp;
01581         a= nu->pntsu*nu->pntsv;
01582         while(a) {
01583             a--;
01584             if(bp->f1 & flag);
01585             else break;
01586             bp++;
01587         }
01588         if(a==0) {
01589             BLI_remlink(editnurb, nu);
01590             keyIndex_delNurb(cu->editnurb, nu);
01591             freeNurb(nu); nu=NULL;
01592         }
01593         else {
01594             /* is nurb in U direction selected */
01595             newv= nu->pntsv;
01596             bp= nu->bp;
01597             for(b=0; b<nu->pntsv; b++) {
01598                 sel= 0;
01599                 for(a=0; a<nu->pntsu; a++, bp++) {
01600                     if(bp->f1 & flag) sel++;
01601                 }
01602                 if(sel==nu->pntsu) {
01603                     newv--;
01604                 }
01605                 else if(sel>=1) {
01606                     /* don't delete */
01607                     break;
01608                 }
01609             }
01610             if(newv!=nu->pntsv && b==nu->pntsv) {
01611                 /* delete */
01612                 bp= nu->bp;
01613                 bpn = newbp =
01614                     (BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
01615                 for(b=0; b<nu->pntsv; b++) {
01616                     if((bp->f1 & flag)==0) {
01617                         memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
01618                         keyIndex_updateBP(cu->editnurb, bp, bpn, nu->pntsu);
01619                         bpn+= nu->pntsu;
01620                     } else {
01621                         keyIndex_delBP(cu->editnurb, bp);
01622                     }
01623                     bp+= nu->pntsu;
01624                 }
01625                 nu->pntsv= newv;
01626                 MEM_freeN(nu->bp);
01627                 nu->bp= newbp;
01628                 clamp_nurb_order_v(nu);
01629 
01630                 nurbs_knot_calc_v(nu);
01631             }
01632             else {
01633                 /* is the nurb in V direction selected */
01634                 newu= nu->pntsu;
01635                 for(a=0; a<nu->pntsu; a++) {
01636                     bp= nu->bp+a;
01637                     sel= 0;
01638                     for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
01639                         if(bp->f1 & flag) sel++;
01640                     }
01641                     if(sel==nu->pntsv) {
01642                         newu--;
01643                     }
01644                     else if(sel>=1) {
01645                         /* don't delete */
01646                         break;
01647                     }
01648                 }
01649                 if(newu!=nu->pntsu && a==nu->pntsu) {
01650                     /* delete */
01651                     bp= nu->bp;
01652                     bpn = newbp =
01653                         (BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
01654                     for(b=0; b<nu->pntsv; b++) {
01655                         for(a=0; a<nu->pntsu; a++, bp++) {
01656                             if((bp->f1 & flag)==0) {
01657                                 *bpn= *bp;
01658                                 keyIndex_updateBP(cu->editnurb, bp, bpn, 1);
01659                                 bpn++;
01660                             } else {
01661                                 keyIndex_delBP(cu->editnurb, bp);
01662                             }
01663                         }
01664                     }
01665                     MEM_freeN(nu->bp);
01666                     nu->bp= newbp;
01667                     if(newu==1 && nu->pntsv>1) {    /* make a U spline */
01668                         nu->pntsu= nu->pntsv;
01669                         nu->pntsv= 1;
01670                         SWAP(short, nu->orderu, nu->orderv);
01671                         clamp_nurb_order_u(nu);
01672                         if(nu->knotsv) MEM_freeN(nu->knotsv);
01673                         nu->knotsv= NULL;
01674                     }
01675                     else {
01676                         nu->pntsu= newu;
01677                         clamp_nurb_order_u(nu);
01678                     }
01679                     nurbs_knot_calc_u(nu);
01680                 }
01681             }
01682         }
01683         nu= next;
01684     }
01685 
01686     if(ED_curve_updateAnimPaths(obedit))
01687         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
01688 
01689     return OPERATOR_FINISHED;
01690 }
01691 
01692 /* only for OB_SURF */
01693 static short extrudeflagNurb(EditNurb *editnurb, int flag)
01694 {
01695     Nurb *nu;
01696     BPoint *bp, *bpn, *newbp;
01697     int ok= 0, a, u, v, len;
01698 
01699     nu= editnurb->nurbs.first;
01700     while(nu) {
01701 
01702         if(nu->pntsv==1) {
01703             bp= nu->bp;
01704             a= nu->pntsu;
01705             while(a) {
01706                 if(bp->f1 & flag);
01707                 else break;
01708                 bp++;
01709                 a--;
01710             }
01711             if(a==0) {
01712                 ok= 1;
01713                 newbp =
01714                     (BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
01715                 ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
01716                 bp= newbp+ nu->pntsu;
01717                 ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu);
01718                 MEM_freeN(nu->bp);
01719                 nu->bp= newbp;
01720                 a= nu->pntsu;
01721                 while(a--) {
01722                     select_bpoint(bp, SELECT, flag, HIDDEN);
01723                     select_bpoint(newbp, DESELECT, flag, HIDDEN);
01724                     bp++; 
01725                     newbp++;
01726                 }
01727 
01728                 nu->pntsv= 2;
01729                 nu->orderv= 2;
01730                 nurbs_knot_calc_v(nu);
01731             }
01732         }
01733         else {
01734             /* which row or column is selected */
01735 
01736             if( isNurbselUV(nu, &u, &v, flag) ) {
01737 
01738                 /* deselect all */
01739                 bp= nu->bp;
01740                 a= nu->pntsu*nu->pntsv;
01741                 while(a--) {
01742                     select_bpoint(bp, DESELECT, flag, HIDDEN);
01743                     bp++;
01744                 }
01745 
01746                 if(u==0 || u== nu->pntsv-1) {       /* row in u-direction selected */
01747                     ok= 1;
01748                     newbp =
01749                         (BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1)
01750                                           * sizeof(BPoint), "extrudeNurb1");
01751                     if(u==0) {
01752                         len= nu->pntsv*nu->pntsu;
01753                         ED_curve_bpcpy(editnurb, newbp+nu->pntsu, nu->bp, len);
01754                         ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
01755                         bp= newbp;
01756                     }
01757                     else {
01758                         len= nu->pntsv*nu->pntsu;
01759                         ED_curve_bpcpy(editnurb, newbp, nu->bp, len);
01760                         ED_curve_bpcpy(editnurb, newbp+len, nu->bp+len-nu->pntsu, nu->pntsu);
01761                         bp= newbp+len;
01762                     }
01763 
01764                     a= nu->pntsu;
01765                     while(a--) {
01766                         select_bpoint(bp, SELECT, flag, HIDDEN);
01767                         bp++;
01768                     }
01769 
01770                     MEM_freeN(nu->bp);
01771                     nu->bp= newbp;
01772                     nu->pntsv++;
01773                     nurbs_knot_calc_v(nu);
01774                 }
01775                 else if(v==0 || v== nu->pntsu-1) {      /* collumn in v-direction selected */
01776                     ok= 1;
01777                     bpn = newbp =
01778                         (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
01779                     bp= nu->bp;
01780 
01781                     for(a=0; a<nu->pntsv; a++) {
01782                         if(v==0) {
01783                             *bpn= *bp;
01784                             bpn->f1 |= flag;
01785                             bpn++;
01786                         }
01787                         ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu);
01788                         bp+= nu->pntsu;
01789                         bpn+= nu->pntsu;
01790                         if(v== nu->pntsu-1) {
01791                             *bpn= *(bp-1);
01792                             bpn->f1 |= flag;
01793                             bpn++;
01794                         }
01795                     }
01796 
01797                     MEM_freeN(nu->bp);
01798                     nu->bp= newbp;
01799                     nu->pntsu++;
01800                     nurbs_knot_calc_u(nu);
01801                 }
01802             }
01803         }
01804         nu= nu->next;
01805     }
01806 
01807     return ok;
01808 }
01809 
01810 static void adduplicateflagNurb(Object *obedit, short flag)
01811 {
01812     ListBase *editnurb= object_editcurve_get(obedit);
01813     Nurb *nu, *newnu;
01814     BezTriple *bezt, *bezt1;
01815     BPoint *bp, *bp1;
01816     Curve *cu= (Curve*)obedit->data;
01817     int a, b, starta, enda, newu, newv;
01818     char *usel;
01819 
01820     cu->lastsel= NULL;
01821 
01822     nu= editnurb->last;
01823     while(nu) {
01824         if(nu->type == CU_BEZIER) {
01825             bezt= nu->bezt;
01826             for(a=0; a<nu->pntsu; a++) {
01827                 enda= -1;
01828                 starta= a;
01829                 while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
01830                     select_beztriple(bezt, DESELECT, flag, HIDDEN);
01831                     enda=a;
01832                     if(a>=nu->pntsu-1) break;
01833                     a++;
01834                     bezt++;
01835                 }
01836                 if(enda>=starta) {
01837                     newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");  
01838                     memcpy(newnu, nu, sizeof(Nurb));
01839                     BLI_addtail(editnurb, newnu);
01840                     set_actNurb(obedit, newnu);
01841                     newnu->pntsu= enda-starta+1;
01842                     newnu->bezt=
01843                         (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");  
01844                     memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
01845 
01846                     b= newnu->pntsu;
01847                     bezt1= newnu->bezt;
01848                     while(b--) {
01849                         select_beztriple(bezt1, SELECT, flag, HIDDEN);
01850                         bezt1++;
01851                     }
01852 
01853                     if(nu->flagu & CU_NURB_CYCLIC) {
01854                         if(starta!=0 || enda!=nu->pntsu-1) {
01855                             newnu->flagu &= ~CU_NURB_CYCLIC;
01856                         }
01857                     }
01858                 }
01859                 bezt++;
01860             }
01861         }
01862         else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
01863             bp= nu->bp;
01864             for(a=0; a<nu->pntsu; a++) {
01865                 enda= -1;
01866                 starta= a;
01867                 while(bp->f1 & flag) {
01868                     select_bpoint(bp, DESELECT, flag, HIDDEN);
01869                     enda= a;
01870                     if(a>=nu->pntsu-1) break;
01871                     a++;
01872                     bp++;
01873                 }
01874                 if(enda>=starta) {
01875                     newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");  
01876                     memcpy(newnu, nu, sizeof(Nurb));
01877                     set_actNurb(obedit, newnu);
01878                     BLI_addtail(editnurb, newnu);
01879                     newnu->pntsu= enda-starta+1;
01880                     newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
01881                     memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
01882 
01883                     b= newnu->pntsu;
01884                     bp1= newnu->bp;
01885                     while(b--) {
01886                         select_bpoint(bp1, SELECT, flag, HIDDEN);
01887                         bp1++;
01888                     }
01889 
01890                     if(nu->flagu & CU_NURB_CYCLIC) {
01891                         if(starta!=0 || enda!=nu->pntsu-1) {
01892                             newnu->flagu &= ~CU_NURB_CYCLIC;
01893                         }
01894                     }
01895 
01896                     /* knots */
01897                     newnu->knotsu= NULL;
01898                     nurbs_knot_calc_u(newnu);
01899                 }
01900                 bp++;
01901             }
01902         }
01903         else {
01904             /* a rectangular area in nurb has to be selected */
01905             if(isNurbsel(nu)) {
01906                 usel= MEM_callocN(nu->pntsu, "adduplicateN4");
01907                 bp= nu->bp;
01908                 for(a=0; a<nu->pntsv; a++) {
01909                     for(b=0; b<nu->pntsu; b++, bp++) {
01910                         if(bp->f1 & flag) usel[b]++;
01911                     }
01912                 }
01913                 newu= 0;
01914                 newv= 0;
01915                 for(a=0; a<nu->pntsu; a++) {
01916                     if(usel[a]) {
01917                         if(newv==0 || usel[a]==newv) {
01918                             newv= usel[a];
01919                             newu++;
01920                         }
01921                         else {
01922                             newv= 0;
01923                             break;
01924                         }
01925                     }
01926                 }
01927                 if(newu==0 || newv==0) {
01928                     if (G.f & G_DEBUG)
01929                         printf("Can't duplicate Nurb\n");
01930                 }
01931                 else {
01932 
01933                     if(newu==1) SWAP(short, newu, newv);
01934 
01935                     newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
01936                     memcpy(newnu, nu, sizeof(Nurb));
01937                     BLI_addtail(editnurb, newnu);
01938                     set_actNurb(obedit, newnu);
01939                     newnu->pntsu= newu;
01940                     newnu->pntsv= newv;
01941                     newnu->bp =
01942                         (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
01943                     clamp_nurb_order_u(newnu);
01944                     clamp_nurb_order_v(newnu);
01945                     
01946                     newnu->knotsu= newnu->knotsv= NULL;
01947                     
01948                     bp= newnu->bp;
01949                     bp1= nu->bp;
01950                     for(a=0; a<nu->pntsv; a++) {
01951                         for(b=0; b<nu->pntsu; b++, bp1++) {
01952                             if(bp1->f1 & flag) {
01953                                 memcpy(bp, bp1, sizeof(BPoint));
01954                                 select_bpoint(bp1, DESELECT, flag, HIDDEN);
01955                                 bp++;
01956                             }
01957                         }
01958                     }
01959                     if (check_valid_nurb_u(newnu)) {
01960                         if(nu->pntsu==newnu->pntsu && nu->knotsu) {
01961                             newnu->knotsu= MEM_dupallocN( nu->knotsu );
01962                         } else {
01963                             nurbs_knot_calc_u(newnu);
01964                         }
01965                     }
01966                     if (check_valid_nurb_v(newnu)) {
01967                         if(nu->pntsv==newnu->pntsv && nu->knotsv) {
01968                             newnu->knotsv= MEM_dupallocN( nu->knotsv );
01969                         } else {
01970                             nurbs_knot_calc_v(newnu);
01971                         }
01972                     }
01973                 }
01974                 MEM_freeN(usel);
01975             }
01976         }
01977 
01978         nu= nu->prev;
01979     }
01980     
01981     /* actnu changed */
01982 }
01983 
01984 /**************** switch direction operator ***************/
01985 
01986 static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
01987 {
01988     Object *obedit= CTX_data_edit_object(C);
01989     Curve *cu= (Curve*)obedit->data;
01990     EditNurb *editnurb= cu->editnurb;
01991     Nurb *nu;
01992 
01993     for(nu= editnurb->nurbs.first; nu; nu= nu->next)
01994         if(isNurbsel(nu)) {
01995             switchdirectionNurb(nu);
01996             keyData_switchDirectionNurb(cu, nu);
01997         }
01998 
01999     if(ED_curve_updateAnimPaths(obedit))
02000         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
02001 
02002     DAG_id_tag_update(obedit->data, 0);
02003     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
02004 
02005     return OPERATOR_FINISHED;
02006 }
02007 
02008 void CURVE_OT_switch_direction(wmOperatorType *ot)
02009 {
02010     /* identifiers */
02011     ot->name= "Switch Direction";
02012     ot->description= "Switch direction of selected splines";
02013     ot->idname= "CURVE_OT_switch_direction";
02014     
02015     /* api callbacks */
02016     ot->exec= switch_direction_exec;
02017     ot->poll= ED_operator_editsurfcurve;
02018 
02019     /* flags */
02020     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02021 }
02022 
02023 /****************** set weight operator *******************/
02024 
02025 static int set_goal_weight_exec(bContext *C, wmOperator *op)
02026 {
02027     Object *obedit= CTX_data_edit_object(C);
02028     ListBase *editnurb= object_editcurve_get(obedit);
02029     Nurb *nu;
02030     BezTriple *bezt;
02031     BPoint *bp;
02032     float weight= RNA_float_get(op->ptr, "weight");
02033     int a;
02034                 
02035     for(nu= editnurb->first; nu; nu= nu->next) {
02036         if(nu->bezt) {
02037             for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
02038                 if(bezt->f2 & SELECT)
02039                     bezt->weight= weight;
02040             }
02041         }
02042         else if(nu->bp) {
02043             for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
02044                 if(bp->f1 & SELECT)
02045                     bp->weight= weight;
02046             }
02047         }
02048     }   
02049 
02050     DAG_id_tag_update(obedit->data, 0);
02051     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
02052 
02053     return OPERATOR_FINISHED;
02054 }
02055 
02056 void CURVE_OT_spline_weight_set(wmOperatorType *ot)
02057 {
02058     /* identifiers */
02059     ot->name= "Set Goal Weight";
02060     ot->description= "Set softbody goal weight for selected points";
02061     ot->idname= "CURVE_OT_spline_weight_set";
02062     
02063     /* api callbacks */
02064     ot->exec= set_goal_weight_exec;
02065     ot->invoke= WM_operator_props_popup;
02066     ot->poll= ED_operator_editsurfcurve;
02067 
02068     /* flags */
02069     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02070 
02071     /* properties */
02072     RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
02073 }
02074 
02075 /******************* set radius operator ******************/
02076 
02077 static int set_radius_exec(bContext *C, wmOperator *op)
02078 {
02079     Object *obedit= CTX_data_edit_object(C);
02080     ListBase *editnurb= object_editcurve_get(obedit);
02081     Nurb *nu;
02082     BezTriple *bezt;
02083     BPoint *bp;
02084     float radius= RNA_float_get(op->ptr, "radius");
02085     int a;
02086     
02087     for(nu= editnurb->first; nu; nu= nu->next) {
02088         if(nu->bezt) {
02089             for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
02090                 if(bezt->f2 & SELECT)
02091                     bezt->radius= radius;
02092             }
02093         }
02094         else if(nu->bp) {
02095             for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
02096                 if(bp->f1 & SELECT)
02097                     bp->radius= radius;
02098             }
02099         }
02100     }   
02101 
02102     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
02103     DAG_id_tag_update(obedit->data, 0);
02104 
02105     return OPERATOR_FINISHED;
02106 }
02107 
02108 void CURVE_OT_radius_set(wmOperatorType *ot)
02109 {
02110     /* identifiers */
02111     ot->name= "Set Curve Radius";
02112     ot->description= "Set per-point radius which is used for bevel tapering";
02113     ot->idname= "CURVE_OT_radius_set";
02114     
02115     /* api callbacks */
02116     ot->exec= set_radius_exec;
02117     ot->invoke= WM_operator_props_popup;
02118     ot->poll= ED_operator_editsurfcurve;
02119 
02120     /* flags */
02121     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02122 
02123     /* properties */
02124     RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "", 0.0001f, 10.0f);
02125 }
02126 
02127 /********************* smooth operator ********************/
02128 
02129 static int smooth_exec(bContext *C, wmOperator *UNUSED(op))
02130 {
02131     Object *obedit= CTX_data_edit_object(C);
02132     ListBase *editnurb= object_editcurve_get(obedit);
02133     Nurb *nu;
02134     BezTriple *bezt, *beztOrig;
02135     BPoint *bp, *bpOrig;
02136     float val, newval, offset;
02137     int a, i, change = 0;
02138     
02139     for(nu= editnurb->first; nu; nu= nu->next) {
02140         if(nu->bezt) {
02141             change = 0;
02142             beztOrig = MEM_dupallocN( nu->bezt );
02143             for(bezt=nu->bezt+1, a=1; a<nu->pntsu-1; a++, bezt++) {
02144                 if(bezt->f2 & SELECT) {
02145                     for(i=0; i<3; i++) {
02146                         val = bezt->vec[1][i];
02147                         newval = ((beztOrig+(a-1))->vec[1][i] * 0.5f) + ((beztOrig+(a+1))->vec[1][i] * 0.5f);
02148                         offset = (val*((1.0f/6.0f)*5.0f)) + (newval*(1.0f/6.0f)) - val;
02149                         /* offset handles */
02150                         bezt->vec[1][i] += offset;
02151                         bezt->vec[0][i] += offset;
02152                         bezt->vec[2][i] += offset;
02153                     }
02154                     change = 1;
02155                 }
02156             }
02157             MEM_freeN(beztOrig);
02158             if (change)
02159                 calchandlesNurb(nu);
02160         } else if (nu->bp) {
02161             bpOrig = MEM_dupallocN( nu->bp );
02162             /* Same as above, keep these the same! */
02163             for(bp=nu->bp+1, a=1; a<nu->pntsu-1; a++, bp++) {
02164                 if(bp->f1 & SELECT) {
02165                     for(i=0; i<3; i++) {
02166                         val = bp->vec[i];
02167                         newval = ((bpOrig+(a-1))->vec[i] * 0.5f) + ((bpOrig+(a+1))->vec[i] * 0.5f);
02168                         offset = (val*((1.0f/6.0f)*5.0f)) + (newval*(1.0f/6.0f)) - val;
02169                     
02170                         bp->vec[i] += offset;
02171                     }
02172                 }
02173             }
02174             MEM_freeN(bpOrig);
02175         }
02176     }
02177 
02178     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
02179     DAG_id_tag_update(obedit->data, 0);
02180 
02181     return OPERATOR_FINISHED;
02182 }
02183 
02184 void CURVE_OT_smooth(wmOperatorType *ot)
02185 {
02186     /* identifiers */
02187     ot->name= "Smooth";
02188     ot->description= "Flatten angles of selected points";
02189     ot->idname= "CURVE_OT_smooth";
02190     
02191     /* api callbacks */
02192     ot->exec= smooth_exec;
02193     ot->poll= ED_operator_editsurfcurve;
02194 
02195     /* flags */
02196     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02197 }
02198 
02199 /**************** smooth curve radius operator *************/
02200 
02201 /* TODO, make smoothing distance based */
02202 static int smooth_radius_exec(bContext *C, wmOperator *UNUSED(op))
02203 {
02204     Object *obedit= CTX_data_edit_object(C);
02205     ListBase *editnurb= object_editcurve_get(obedit);
02206     Nurb *nu;
02207     BezTriple *bezt;
02208     BPoint *bp;
02209     int a;
02210     
02211     /* use for smoothing */
02212     int last_sel;
02213     int start_sel, end_sel; /* selection indices, inclusive */
02214     float start_rad, end_rad, fac, range;
02215     
02216     for(nu= editnurb->first; nu; nu= nu->next) {
02217         if(nu->bezt) {
02218             
02219             for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
02220                 /* loop over selection segments of a curve, smooth each */
02221                 
02222                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
02223                 start_sel = -1;
02224                 for(bezt=nu->bezt+last_sel, a=last_sel; a<nu->pntsu; a++, bezt++) {
02225                     if(bezt->f2 & SELECT) {
02226                         start_sel = a;
02227                         break;
02228                     }
02229                 }
02230                 /* incase there are no other selected verts */
02231                 end_sel = start_sel;
02232                 for(bezt=nu->bezt+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bezt++) {
02233                     if((bezt->f2 & SELECT)==0) {
02234                         break;
02235                     }
02236                     end_sel = a;
02237                 }
02238                 
02239                 if (start_sel == -1) {
02240                     last_sel = nu->pntsu; /* next... */
02241                 } else {
02242                     last_sel = end_sel; /* before we modify it */
02243                     
02244                     /* now blend between start and end sel */
02245                     start_rad = end_rad = -1.0;
02246                     
02247                     if (start_sel == end_sel) {
02248                         /* simple, only 1 point selected */
02249                         if (start_sel>0)                        start_rad = (nu->bezt+start_sel-1)->radius;
02250                         if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bezt+start_sel+1)->radius;
02251                         
02252                         if (start_rad >= 0.0f && end_rad >= 0.0f)   (nu->bezt+start_sel)->radius = (start_rad + end_rad)/2;
02253                         else if (start_rad >= 0.0f)             (nu->bezt+start_sel)->radius = start_rad;
02254                         else if (end_rad >= 0.0f)               (nu->bezt+start_sel)->radius = end_rad;
02255                     } else {
02256                         /* if endpoints selected, then use them */
02257                         if (start_sel==0) {
02258                             start_rad = (nu->bezt+start_sel)->radius;
02259                             start_sel++; /* we dont want to edit the selected endpoint */
02260                         } else {
02261                             start_rad = (nu->bezt+start_sel-1)->radius;
02262                         }
02263                         if (end_sel==nu->pntsu-1) {
02264                             end_rad = (nu->bezt+end_sel)->radius;
02265                             end_sel--; /* we dont want to edit the selected endpoint */
02266                         } else {
02267                             end_rad = (nu->bezt+end_sel+1)->radius;
02268                         }
02269                         
02270                         /* Now Blend between the points */
02271                         range = (float)(end_sel - start_sel) + 2.0f;
02272                         for(bezt=nu->bezt+start_sel, a=start_sel; a<=end_sel; a++, bezt++) {
02273                             fac = (float)(1+a-start_sel) / range;
02274                             bezt->radius = start_rad*(1.0f-fac) + end_rad*fac;
02275                         }
02276                     }
02277                 }
02278             }
02279         } else if (nu->bp) {
02280             /* Same as above, keep these the same! */
02281             for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
02282                 /* loop over selection segments of a curve, smooth each */
02283                 
02284                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
02285                 start_sel = -1;
02286                 for(bp=nu->bp+last_sel, a=last_sel; a<nu->pntsu; a++, bp++) {
02287                     if(bp->f1 & SELECT) {
02288                         start_sel = a;
02289                         break;
02290                     }
02291                 }
02292                 /* incase there are no other selected verts */
02293                 end_sel = start_sel;
02294                 for(bp=nu->bp+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bp++) {
02295                     if((bp->f1 & SELECT)==0) {
02296                         break;
02297                     }
02298                     end_sel = a;
02299                 }
02300                 
02301                 if (start_sel == -1) {
02302                     last_sel = nu->pntsu; /* next... */
02303                 } else {
02304                     last_sel = end_sel; /* before we modify it */
02305                     
02306                     /* now blend between start and end sel */
02307                     start_rad = end_rad = -1.0;
02308                     
02309                     if (start_sel == end_sel) {
02310                         /* simple, only 1 point selected */
02311                         if (start_sel>0)                        start_rad = (nu->bp+start_sel-1)->radius;
02312                         if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bp+start_sel+1)->radius;
02313                         
02314                         if (start_rad >= 0.0f && end_rad >= 0.0f)   (nu->bp+start_sel)->radius = (start_rad + end_rad)/2;
02315                         else if (start_rad >= 0.0f)                 (nu->bp+start_sel)->radius = start_rad;
02316                         else if (end_rad >= 0.0f)                   (nu->bp+start_sel)->radius = end_rad;
02317                     } else {
02318                         /* if endpoints selected, then use them */
02319                         if (start_sel==0) {
02320                             start_rad = (nu->bp+start_sel)->radius;
02321                             start_sel++; /* we dont want to edit the selected endpoint */
02322                         } else {
02323                             start_rad = (nu->bp+start_sel-1)->radius;
02324                         }
02325                         if (end_sel==nu->pntsu-1) {
02326                             end_rad = (nu->bp+end_sel)->radius;
02327                             end_sel--; /* we dont want to edit the selected endpoint */
02328                         } else {
02329                             end_rad = (nu->bp+end_sel+1)->radius;
02330                         }
02331                         
02332                         /* Now Blend between the points */
02333                         range = (float)(end_sel - start_sel) + 2.0f;
02334                         for(bp=nu->bp+start_sel, a=start_sel; a<=end_sel; a++, bp++) {
02335                             fac = (float)(1+a-start_sel) / range;
02336                             bp->radius = start_rad*(1.0f-fac) + end_rad*fac;
02337                         }
02338                     }
02339                 }
02340             }
02341         }
02342     }
02343 
02344     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
02345     DAG_id_tag_update(obedit->data, 0);
02346 
02347     return OPERATOR_FINISHED;
02348 }
02349 
02350 void CURVE_OT_smooth_radius(wmOperatorType *ot)
02351 {
02352     /* identifiers */
02353     ot->name= "Smooth Curve Radius";
02354     ot->description= "Flatten radiuses of selected points";
02355     ot->idname= "CURVE_OT_smooth_radius";
02356     
02357     /* api clastbacks */
02358     ot->exec= smooth_radius_exec;
02359     ot->poll= ED_operator_editsurfcurve;
02360     
02361     /* flags */
02362     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02363 }
02364 
02365 /***************** selection utility *************************/
02366 
02367 /* next == 1 -> select next         */
02368 /* next == -1 -> select previous    */
02369 /* cont == 1 -> select continuously     */
02370 /* selstatus, inverts behaviour     */
02371 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus)
02372 {
02373     Nurb *nu;
02374     BezTriple *bezt;
02375     BPoint *bp;
02376     int a;
02377     short lastsel= 0;
02378     
02379     if(next==0) return;
02380     
02381     for(nu= editnurb->first; nu; nu= nu->next) {
02382         lastsel=0;
02383         if(nu->type == CU_BEZIER) {         
02384             a= nu->pntsu;
02385             bezt= nu->bezt;
02386             if(next < 0) bezt= (nu->bezt + (a-1));
02387             while(a--) {
02388                 if(a-abs(next) < 0) break;
02389                 if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & SELECT) || (selstatus==0))) {
02390                     bezt+=next;
02391                     if(!(bezt->f2 & SELECT) || (selstatus==0)) {
02392                         short sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
02393                         if((sel==1) && (cont==0)) lastsel= 1;
02394                     }
02395                 }
02396                 else {
02397                     bezt+=next;
02398                     lastsel= 0;
02399                 }
02400                 /* move around in zigzag way so that we go through each */              
02401                 bezt-=(next-next/abs(next));                
02402             }
02403         }
02404         else {
02405             a= nu->pntsu*nu->pntsv;
02406             bp= nu->bp;
02407             if(next < 0) bp= (nu->bp + (a-1));
02408             while(a--) {
02409                 if(a-abs(next) < 0) break;
02410                 if((lastsel==0) && (bp->hide==0) && ((bp->f1 & SELECT) || (selstatus==0))) {
02411                     bp+=next;
02412                     if(!(bp->f1 & SELECT) || (selstatus==0)) {
02413                         short sel= select_bpoint(bp, selstatus, 1, VISIBLE);
02414                         if((sel==1) && (cont==0)) lastsel= 1;
02415                     }           
02416                 }
02417                 else {
02418                     bp+=next;
02419                     lastsel= 0;
02420                 }
02421                 /* move around in zigzag way so that we go through each */
02422                 bp-=(next-next/abs(next));              
02423             }
02424         }
02425     }
02426 }
02427 
02428 /**************** select start/end operators **************/
02429 
02430 /* (de)selects first or last of visible part of each Nurb depending on selFirst     */
02431 /* selFirst: defines the end of which to select                     */
02432 /* doswap: defines if selection state of each first/last control point is swapped   */
02433 /* selstatus: selection status in case doswap is false                  */
02434 void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus)
02435 {
02436     ListBase *editnurb= object_editcurve_get(obedit);
02437     Nurb *nu;
02438     BPoint *bp;
02439     BezTriple *bezt;
02440     Curve *cu;
02441     int a;
02442 
02443     if(obedit==NULL) return;
02444 
02445     cu= (Curve*)obedit->data;
02446     cu->lastsel= NULL;
02447 
02448     for(nu= editnurb->first; nu; nu= nu->next) {
02449         if(nu->type == CU_BEZIER) {
02450             a= nu->pntsu;
02451             
02452             /* which point? */
02453             if(selfirst==0) { /* select last */ 
02454                 bezt= (nu->bezt + (a-1));
02455             }
02456             else { /* select first */
02457                 bezt= nu->bezt;
02458             }
02459             
02460             while(a--) {
02461                 short sel;
02462                 if(doswap) sel= swap_selection_beztriple(bezt);
02463                 else sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
02464                 
02465                 if(sel==1) break;
02466             }
02467         }
02468         else {
02469             a= nu->pntsu*nu->pntsv;
02470             
02471             /* which point? */
02472             if(selfirst==0) { /* select last */
02473                 bp= (nu->bp + (a-1));
02474             }
02475             else{ /* select first */
02476                 bp= nu->bp;
02477             }
02478 
02479             while(a--) {
02480                 if (bp->hide == 0) {
02481                     short sel;
02482                     if(doswap) sel= swap_selection_bpoint(bp);
02483                     else sel= select_bpoint(bp, selstatus, 1, VISIBLE);
02484                     
02485                     if(sel==1) break;
02486                 }
02487             }
02488         }
02489     }
02490 }
02491 
02492 static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
02493 {
02494     Object *obedit= CTX_data_edit_object(C);
02495 
02496     selectend_nurb(obedit, FIRST, 1, DESELECT);
02497     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02498 
02499     return OPERATOR_FINISHED;
02500 }
02501 
02502 void CURVE_OT_de_select_first(wmOperatorType *ot)
02503 {
02504     /* identifiers */
02505     ot->name= "Select or Deselect First";
02506     ot->idname= "CURVE_OT_de_select_first";
02507     
02508     /* api cfirstbacks */
02509     ot->exec= de_select_first_exec;
02510     ot->poll= ED_operator_editcurve;
02511     
02512     /* flags */
02513     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02514 }
02515 
02516 static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
02517 {
02518     Object *obedit= CTX_data_edit_object(C);
02519 
02520     selectend_nurb(obedit, LAST, 1, DESELECT);
02521     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02522 
02523     return OPERATOR_FINISHED;
02524 }
02525 
02526 void CURVE_OT_de_select_last(wmOperatorType *ot)
02527 {
02528     /* identifiers */
02529     ot->name= "Select or Deselect Last";
02530     ot->idname= "CURVE_OT_de_select_last";
02531     
02532     /* api clastbacks */
02533     ot->exec= de_select_last_exec;
02534     ot->poll= ED_operator_editcurve;
02535     
02536     /* flags */
02537     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02538 }
02539 
02540 /******************* de select all operator ***************/
02541 
02542 static short nurb_has_selected_cps(ListBase *editnurb)
02543 {
02544     Nurb *nu;
02545     BezTriple *bezt;
02546     BPoint *bp;
02547     int a;
02548 
02549     for(nu= editnurb->first; nu; nu= nu->next) {
02550         if(nu->type == CU_BEZIER) {
02551             a= nu->pntsu;
02552             bezt= nu->bezt;
02553             while(a--) {
02554                 if(bezt->hide==0) {
02555                     if((bezt->f1 & SELECT)
02556                     || (bezt->f2 & SELECT)
02557                     || (bezt->f3 & SELECT)) return 1;
02558                 }
02559                 bezt++;
02560             }
02561         }
02562         else {
02563             a= nu->pntsu*nu->pntsv;
02564             bp= nu->bp;
02565             while(a--) {
02566                 if((bp->hide==0) && (bp->f1 & SELECT)) return 1;
02567                 bp++;
02568             }
02569         }
02570     }
02571     
02572     return 0;
02573 }
02574 
02575 static int de_select_all_exec(bContext *C, wmOperator *op)
02576 {
02577     Object *obedit= CTX_data_edit_object(C);
02578     ListBase *editnurb= object_editcurve_get(obedit);
02579     int action = RNA_enum_get(op->ptr, "action");
02580 
02581     if (action == SEL_TOGGLE) {
02582         action = SEL_SELECT;
02583         if(nurb_has_selected_cps(editnurb))
02584             action = SEL_DESELECT;
02585     }
02586 
02587     switch (action) {
02588         case SEL_SELECT:
02589             CU_select_all(obedit);
02590             break;
02591         case SEL_DESELECT:
02592             CU_deselect_all(obedit);
02593             break;
02594         case SEL_INVERT:
02595             CU_select_swap(obedit);
02596             break;
02597     }
02598     
02599     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02600 
02601     return OPERATOR_FINISHED;
02602 }
02603 
02604 void CURVE_OT_select_all(wmOperatorType *ot)
02605 {
02606     /* identifiers */
02607     ot->name= "Select or Deselect All";
02608     ot->idname= "CURVE_OT_select_all";
02609     
02610     /* api callbacks */
02611     ot->exec= de_select_all_exec;
02612     ot->poll= ED_operator_editsurfcurve;
02613     
02614     /* flags */
02615     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02616 
02617     /* properties */
02618     WM_operator_properties_select_all(ot);
02619 }
02620 
02621 /********************** hide operator *********************/
02622 
02623 static int hide_exec(bContext *C, wmOperator *op)
02624 {
02625     Object *obedit= CTX_data_edit_object(C);
02626     Curve *cu= obedit->data;
02627     ListBase *editnurb= object_editcurve_get(obedit);
02628     Nurb *nu;
02629     BPoint *bp;
02630     BezTriple *bezt;
02631     int a, sel, invert= RNA_boolean_get(op->ptr, "unselected");
02632 
02633     for(nu= editnurb->first; nu; nu= nu->next) {
02634         if(nu->type == CU_BEZIER) {
02635             bezt= nu->bezt;
02636             a= nu->pntsu;
02637             sel= 0;
02638             while(a--) {
02639                 if(invert == 0 && BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
02640                     select_beztriple(bezt, DESELECT, 1, HIDDEN);
02641                     bezt->hide= 1;
02642                 }
02643                 else if(invert && !BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
02644                     select_beztriple(bezt, DESELECT, 1, HIDDEN);
02645                     bezt->hide= 1;
02646                 }
02647                 if(bezt->hide) sel++;
02648                 bezt++;
02649             }
02650             if(sel==nu->pntsu) nu->hide= 1;
02651         }
02652         else {
02653             bp= nu->bp;
02654             a= nu->pntsu*nu->pntsv;
02655             sel= 0;
02656             while(a--) {
02657                 if(invert==0 && (bp->f1 & SELECT)) {
02658                     select_bpoint(bp, DESELECT, 1, HIDDEN);
02659                     bp->hide= 1;
02660                 }
02661                 else if(invert && (bp->f1 & SELECT)==0) {
02662                     select_bpoint(bp, DESELECT, 1, HIDDEN);
02663                     bp->hide= 1;
02664                 }
02665                 if(bp->hide) sel++;
02666                 bp++;
02667             }
02668             if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
02669         }
02670     }
02671 
02672     DAG_id_tag_update(obedit->data, 0);
02673     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02674 
02675     return OPERATOR_FINISHED;   
02676 }
02677 
02678 void CURVE_OT_hide(wmOperatorType *ot)
02679 {
02680     /* identifiers */
02681     ot->name= "Hide Selected";
02682     ot->idname= "CURVE_OT_hide";
02683     
02684     /* api callbacks */
02685     ot->exec= hide_exec;
02686     ot->poll= ED_operator_editsurfcurve;
02687     
02688     /* flags */
02689     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02690     
02691     /* props */
02692     RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
02693 }
02694 
02695 /********************** reveal operator *********************/
02696 
02697 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
02698 {
02699     Object *obedit= CTX_data_edit_object(C);
02700     ListBase *editnurb= object_editcurve_get(obedit);
02701     Nurb *nu;
02702     BPoint *bp;
02703     BezTriple *bezt;
02704     int a;
02705 
02706     for(nu= editnurb->first; nu; nu= nu->next) {
02707         nu->hide= 0;
02708         if(nu->type == CU_BEZIER) {
02709             bezt= nu->bezt;
02710             a= nu->pntsu;
02711             while(a--) {
02712                 if(bezt->hide) {
02713                     select_beztriple(bezt, SELECT, 1, HIDDEN);
02714                     bezt->hide= 0;
02715                 }
02716                 bezt++;
02717             }
02718         }
02719         else {
02720             bp= nu->bp;
02721             a= nu->pntsu*nu->pntsv;
02722             while(a--) {
02723                 if(bp->hide) {
02724                     select_bpoint(bp, SELECT, 1, HIDDEN);
02725                     bp->hide= 0;
02726                 }
02727                 bp++;
02728             }
02729         }
02730     }
02731 
02732     DAG_id_tag_update(obedit->data, 0);
02733     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02734 
02735     return OPERATOR_FINISHED;   
02736 }
02737 
02738 void CURVE_OT_reveal(wmOperatorType *ot)
02739 {
02740     /* identifiers */
02741     ot->name= "Reveal Hidden";
02742     ot->idname= "CURVE_OT_reveal";
02743     
02744     /* api callbacks */
02745     ot->exec= reveal_exec;
02746     ot->poll= ED_operator_editsurfcurve;
02747     
02748     /* flags */
02749     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02750 }
02751 
02752 /********************** subdivide operator *********************/
02753 
02758 static void subdividenurb(Object *obedit, int number_cuts)
02759 {
02760     Curve *cu= obedit->data;
02761     EditNurb *editnurb= cu->editnurb;
02762     Nurb *nu;
02763     BezTriple *prevbezt, *bezt, *beztnew, *beztn;
02764     BPoint *bp, *prevbp, *bpnew, *bpn;
02765     float vec[15];
02766     int a, b, sel, amount, *usel, *vsel, i;
02767     float factor;
02768 
02769     // printf("*** subdivideNurb: entering subdivide\n");
02770 
02771     for(nu= editnurb->nurbs.first; nu; nu= nu->next) {
02772         amount= 0;
02773         if(nu->type == CU_BEZIER) {
02774         /* 
02775            Insert a point into a 2D Bezier curve. 
02776            Endpoints are preserved. Otherwise, all selected and inserted points are 
02777            newly created. Old points are discarded.
02778         */
02779             /* count */
02780             if(nu->flagu & CU_NURB_CYCLIC) {
02781                 a= nu->pntsu;
02782                 bezt= nu->bezt;
02783                 prevbezt= bezt+(a-1);
02784             }
02785             else {
02786                 a= nu->pntsu-1;
02787                 prevbezt= nu->bezt;
02788                 bezt= prevbezt+1;
02789             }
02790             while(a--) {
02791                 if( BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) amount+=number_cuts;
02792                 prevbezt= bezt;
02793                 bezt++;
02794             }
02795 
02796             if(amount) {
02797                 /* insert */
02798                 beztnew =
02799                     (BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
02800                 beztn= beztnew;
02801                 if(nu->flagu & CU_NURB_CYCLIC) {
02802                     a= nu->pntsu;
02803                     bezt= nu->bezt;
02804                     prevbezt= bezt+(a-1);
02805                 }
02806                 else {
02807                     a= nu->pntsu-1;
02808                     prevbezt= nu->bezt;
02809                     bezt= prevbezt+1;
02810                 }
02811                 while(a--) {
02812                     memcpy(beztn, prevbezt, sizeof(BezTriple));
02813                     keyIndex_updateBezt(editnurb, prevbezt, beztn, 1);
02814                     beztn++;
02815 
02816                     if( BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
02817                         float prevvec[3][3];
02818 
02819                         memcpy(prevvec, prevbezt->vec, sizeof(float) * 9);
02820 
02821                         for (i = 0; i < number_cuts; i++) {
02822                             factor = 1.0f / (number_cuts + 1 - i);
02823 
02824                             memcpy(beztn, bezt, sizeof(BezTriple));
02825 
02826                             /* midpoint subdividing */
02827                             interp_v3_v3v3(vec, prevvec[1], prevvec[2], factor);
02828                             interp_v3_v3v3(vec+3, prevvec[2], bezt->vec[0], factor);
02829                             interp_v3_v3v3(vec+6, bezt->vec[0], bezt->vec[1], factor);
02830 
02831                             interp_v3_v3v3(vec+9, vec, vec+3, factor);
02832                             interp_v3_v3v3(vec+12, vec+3, vec+6, factor);
02833 
02834                             /* change handle of prev beztn */
02835                             copy_v3_v3((beztn-1)->vec[2], vec);
02836                             /* new point */
02837                             copy_v3_v3(beztn->vec[0], vec+9);
02838                             interp_v3_v3v3(beztn->vec[1], vec+9, vec+12, factor);
02839                             copy_v3_v3(beztn->vec[2], vec+12);
02840                             /* handle of next bezt */
02841                             if(a==0 && i == number_cuts - 1 && (nu->flagu & CU_NURB_CYCLIC)) {copy_v3_v3(beztnew->vec[0], vec+6);}
02842                             else {copy_v3_v3(bezt->vec[0], vec+6);}
02843 
02844                             beztn->radius = (prevbezt->radius + bezt->radius)/2;
02845                             beztn->weight = (prevbezt->weight + bezt->weight)/2;
02846 
02847                             memcpy(prevvec, beztn->vec, sizeof(float) * 9);
02848                             beztn++;
02849                         }
02850                     }
02851 
02852                     prevbezt= bezt;
02853                     bezt++;
02854                 }
02855                 /* last point */
02856                 if((nu->flagu & CU_NURB_CYCLIC)==0) {
02857                     memcpy(beztn, prevbezt, sizeof(BezTriple));
02858                     keyIndex_updateBezt(editnurb, prevbezt, beztn, 1);
02859                 }
02860 
02861                 MEM_freeN(nu->bezt);
02862                 nu->bezt= beztnew;
02863                 nu->pntsu+= amount;
02864 
02865                 calchandlesNurb(nu);
02866             }
02867         } /* End of 'if(nu->type == CU_BEZIER)' */
02868         else if (nu->pntsv==1) {
02869         /* 
02870            All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves 
02871            are handled together with the regular NURB plane division, as it 
02872            should be. I split it off just now, let's see if it is
02873            stable... nzc 30-5-'00
02874          */
02875             /* count */
02876             if(nu->flagu & CU_NURB_CYCLIC) {
02877                 a= nu->pntsu;
02878                 bp= nu->bp;
02879                 prevbp= bp+(a-1);
02880             }
02881             else {
02882                 a= nu->pntsu-1;
02883                 prevbp= nu->bp;
02884                 bp= prevbp+1;
02885             }
02886             while(a--) {
02887                 if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount+=number_cuts;
02888                 prevbp= bp;
02889                 bp++;
02890             }
02891 
02892             if(amount) {
02893                 /* insert */
02894                 bpnew =
02895                     (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
02896                 bpn= bpnew;
02897 
02898                 if(nu->flagu & CU_NURB_CYCLIC) {
02899                     a= nu->pntsu;
02900                     bp= nu->bp;
02901                     prevbp= bp+(a-1);
02902                 }
02903                 else {
02904                     a= nu->pntsu-1;
02905                     prevbp= nu->bp;
02906                     bp= prevbp+1;
02907                 }
02908                 while(a--) {
02909                     memcpy(bpn, prevbp, sizeof(BPoint));
02910                     keyIndex_updateBP(editnurb, prevbp, bpn, 1);
02911                     bpn++;
02912 
02913                     if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) {
02914                  // printf("*** subdivideNurb: insert 'linear' point\n");
02915                         for (i = 0; i < number_cuts; i++) {
02916                             factor = (float)(i + 1) / (number_cuts + 1);
02917 
02918                             memcpy(bpn, bp, sizeof(BPoint));
02919                             interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
02920                             bpn++;
02921                         }
02922 
02923                     }
02924                     prevbp= bp;
02925                     bp++;
02926                 }
02927                 if((nu->flagu & CU_NURB_CYCLIC)==0) { /* last point */
02928                     memcpy(bpn, prevbp, sizeof(BPoint));
02929                     keyIndex_updateBP(editnurb, prevbp, bpn, 1);
02930                 }
02931 
02932                 MEM_freeN(nu->bp);
02933                 nu->bp= bpnew;
02934                 nu->pntsu+= amount;
02935 
02936                 if(nu->type & CU_NURBS) {
02937                     nurbs_knot_calc_u(nu);
02938                 }
02939             }
02940         } /* End of 'else if(nu->pntsv==1)' */
02941         else if(nu->type == CU_NURBS) {
02942         /* This is a very strange test ... */
02984             /* selection-arrays */
02985             usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
02986             vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
02987             sel= 0;
02988 
02989          /* Count the number of selected points. */
02990             bp= nu->bp;
02991             for(a=0; a<nu->pntsv; a++) {
02992                 for(b=0; b<nu->pntsu; b++) {
02993                     if(bp->f1 & SELECT) {
02994                         usel[b]++;
02995                         vsel[a]++;
02996                         sel++;
02997                     }
02998                     bp++;
02999                 }
03000             }
03001             if( sel == (nu->pntsu*nu->pntsv) ) {    /* subdivide entire nurb */
03002            /* Global subdivision is a special case of partial
03003               subdivision. Strange it is considered separately... */
03004 
03005                 /* count of nodes (after subdivision) along U axis */
03006                 int countu= nu->pntsu + (nu->pntsu - 1) * number_cuts;
03007 
03008                 /* total count of nodes after subdivision */
03009                 int tot= ((number_cuts+1)*nu->pntsu-number_cuts)*((number_cuts+1)*nu->pntsv-number_cuts);
03010 
03011                 bpn=bpnew= MEM_mallocN( tot*sizeof(BPoint), "subdivideNurb4");
03012                 bp= nu->bp;
03013                 /* first subdivide rows */
03014                 for(a=0; a<nu->pntsv; a++) {
03015                     for(b=0; b<nu->pntsu; b++) {
03016                         *bpn= *bp;
03017                         keyIndex_updateBP(editnurb, bp, bpn, 1);
03018                         bpn++; 
03019                         bp++;
03020                         if(b<nu->pntsu-1) {
03021                             prevbp= bp-1;
03022                             for (i = 0; i < number_cuts; i++) {
03023                                 factor = (float)(i + 1) / (number_cuts + 1);
03024                                 *bpn= *bp;
03025                                 interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
03026                                 bpn++;
03027                             }
03028                         }
03029                     }
03030                     bpn+= number_cuts * countu;
03031                 }
03032                 /* now insert new */
03033                 bpn= bpnew+((number_cuts+1)*nu->pntsu - number_cuts);
03034                 bp= bpnew+(number_cuts+1)*((number_cuts+1)*nu->pntsu-number_cuts);
03035                 prevbp= bpnew;
03036                 for(a=1; a<nu->pntsv; a++) {
03037 
03038                     for(b=0; b<(number_cuts+1)*nu->pntsu-number_cuts; b++) {
03039                         BPoint *tmp= bpn;
03040                         for (i = 0; i < number_cuts; i++) {
03041                             factor = (float)(i + 1) / (number_cuts + 1);
03042                             *tmp= *bp;
03043                             interp_v4_v4v4(tmp->vec, prevbp->vec, bp->vec, factor);
03044                             tmp += countu;
03045                         }
03046                         bp++; 
03047                         prevbp++;
03048                         bpn++;
03049                     }
03050                     bp+= number_cuts * countu;
03051                     bpn+= number_cuts * countu;
03052                     prevbp+= number_cuts * countu;
03053                 }
03054                 MEM_freeN(nu->bp);
03055                 nu->bp= bpnew;
03056                 nu->pntsu= (number_cuts+1)*nu->pntsu-number_cuts;
03057                 nu->pntsv= (number_cuts+1)*nu->pntsv-number_cuts;
03058                 nurbs_knot_calc_u(nu);
03059                 nurbs_knot_calc_v(nu);
03060             } /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */
03061             else {
03062                 /* subdivide in v direction? */
03063                 sel= 0;
03064                 for(a=0; a<nu->pntsv-1; a++) {
03065                     if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel+=number_cuts;
03066                 }
03067 
03068                 if(sel) {   /* V ! */
03069                     bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4");
03070                     bp= nu->bp;
03071                     for(a=0; a<nu->pntsv; a++) {
03072                         for(b=0; b<nu->pntsu; b++) {
03073                             *bpn= *bp;
03074                             keyIndex_updateBP(editnurb, bp, bpn, 1);
03075                             bpn++;
03076                             bp++;
03077                         }
03078                         if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) {
03079                             for (i = 0; i < number_cuts; i++) {
03080                                 factor = (float)(i + 1) / (number_cuts + 1);
03081                                 prevbp= bp- nu->pntsu;
03082                                 for(b=0; b<nu->pntsu; b++) {
03083                                         /*
03084                                           This simple bisection must be replaces by a
03085                                           subtle resampling of a number of points. Our
03086                                           task is made slightly easier because each
03087                                           point in our curve is a separate data
03088                                           node. (is it?)
03089                                         */
03090                                         *bpn= *prevbp;
03091                                         interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
03092                                         bpn++;
03093 
03094                                     prevbp++;
03095                                     bp++;
03096                                 }
03097                                 bp-= nu->pntsu;
03098                             }
03099                         }
03100                     }
03101                     MEM_freeN(nu->bp);
03102                     nu->bp= bpnew;
03103                     nu->pntsv+= sel;
03104                     nurbs_knot_calc_v(nu);
03105                 }
03106                 else {
03107                     /* or in u direction? */
03108                     sel= 0;
03109                     for(a=0; a<nu->pntsu-1; a++) {
03110                         if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel+=number_cuts;
03111                     }
03112 
03113                     if(sel) {   /* U ! */
03114                  /* Inserting U points is sort of 'default' Flat curves only get */
03115                  /* U points inserted in them.                                   */
03116                         bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4");
03117                         bp= nu->bp;
03118                         for(a=0; a<nu->pntsv; a++) {
03119                             for(b=0; b<nu->pntsu; b++) {
03120                                 *bpn= *bp;
03121                                 keyIndex_updateBP(editnurb, bp, bpn, 1);
03122                                 bpn++; 
03123                                 bp++;
03124                                 if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) {
03125                                     /*
03126                                        One thing that bugs me here is that the
03127                                        orders of things are not the same as in
03128                                        the JW piece. Also, this implies that we
03129                                        handle at most 3rd order curves? I miss
03130                                        some symmetry here...
03131                                     */
03132                                     for (i = 0; i < number_cuts; i++) {
03133                                         factor = (float)(i + 1) / (number_cuts + 1);
03134                                     prevbp= bp- 1;
03135                                     *bpn= *prevbp;
03136                                     interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
03137                                     bpn++;
03138                                     }
03139                                 }
03140                             }
03141                         }
03142                         MEM_freeN(nu->bp);
03143                         nu->bp= bpnew;
03144                         nu->pntsu+= sel;
03145                         nurbs_knot_calc_u(nu); /* shift knots forward */
03146                     }
03147                 }
03148             }
03149             MEM_freeN(usel); 
03150             MEM_freeN(vsel);
03151 
03152         } /* End of 'if(nu->type == CU_NURBS)'  */
03153     }
03154 }
03155 
03156 static int subdivide_exec(bContext *C, wmOperator *op)
03157 {
03158     Object *obedit= CTX_data_edit_object(C);
03159     int number_cuts= RNA_int_get(op->ptr, "number_cuts");
03160 
03161     subdividenurb(obedit, number_cuts);
03162 
03163     if(ED_curve_updateAnimPaths(obedit))
03164         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
03165 
03166     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
03167     DAG_id_tag_update(obedit->data, 0);
03168 
03169     return OPERATOR_FINISHED;   
03170 }
03171 
03172 void CURVE_OT_subdivide(wmOperatorType *ot)
03173 {
03174     /* identifiers */
03175     ot->name= "Subdivide";
03176     ot->description= "Subdivide selected segments";
03177     ot->idname= "CURVE_OT_subdivide";
03178     
03179     /* api callbacks */
03180     ot->exec= subdivide_exec;
03181     ot->poll= ED_operator_editsurfcurve;
03182     
03183     /* flags */
03184     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03185 
03186     RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of cuts", "", 1, 10);
03187 }
03188 
03189 /******************** find nearest ************************/
03190 
03191 static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
03192 {
03193     struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; int dist, hpoint, select, mval[2]; } *data = userData;
03194 
03195     short flag;
03196     short temp;
03197 
03198     if (bp) {
03199         flag = bp->f1;
03200     } else {
03201         if (beztindex==0) {
03202             flag = bezt->f1;
03203         } else if (beztindex==1) {
03204             flag = bezt->f2;
03205         } else {
03206             flag = bezt->f3;
03207         }
03208     }
03209 
03210     temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
03211     if ((flag&1)==data->select) temp += 5;
03212     if (bezt && beztindex==1) temp += 3; /* middle points get a small disadvantage */
03213 
03214     if (temp<data->dist) {
03215         data->dist = temp;
03216 
03217         data->bp = bp;
03218         data->bezt = bezt;
03219         data->nurb = nu;
03220         data->hpoint = bezt?beztindex:0;
03221     }
03222 }
03223 
03224 static short findnearestNurbvert(ViewContext *vc, short sel, const int mval[2], Nurb **nurb, BezTriple **bezt, BPoint **bp)
03225 {
03226         /* sel==1: selected gets a disadvantage */
03227         /* in nurb and bezt or bp the nearest is written */
03228         /* return 0 1 2: handlepunt */
03229     struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; int dist, hpoint, select, mval[2]; } data = {NULL};
03230 
03231     data.dist = 100;
03232     data.hpoint = 0;
03233     data.select = sel;
03234     data.mval[0] = mval[0];
03235     data.mval[1] = mval[1];
03236 
03237     ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
03238     nurbs_foreachScreenVert(vc, findnearestNurbvert__doClosest, &data);
03239 
03240     *nurb = data.nurb;
03241     *bezt = data.bezt;
03242     *bp = data.bp;
03243 
03244     return data.hpoint;
03245 }
03246 
03247 static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt, BPoint **bp)
03248 {
03249     /* in nu and (bezt or bp) selected are written if there's 1 sel.  */
03250     /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
03251     Nurb *nu1;
03252     BezTriple *bezt1;
03253     BPoint *bp1;
03254     int a;
03255 
03256     *nu= NULL;
03257     *bezt= NULL;
03258     *bp= NULL;
03259     for(nu1= editnurb->first; nu1; nu1= nu1->next) {
03260         if(nu1->type == CU_BEZIER) {
03261             bezt1= nu1->bezt;
03262             a= nu1->pntsu;
03263             while(a--) {
03264                 if( (bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT) ) {
03265                     if(*nu != NULL && *nu != nu1) {
03266                         *nu= NULL;
03267                         *bp= NULL;
03268                         *bezt= NULL;
03269                         return;
03270                     }
03271                     else if(*bezt || *bp) {
03272                         *bp= NULL;
03273                         *bezt= NULL;
03274                     }
03275                     else {
03276                         *bezt= bezt1;
03277                         *nu= nu1;
03278                     }
03279                 }
03280                 bezt1++;
03281             }
03282         }
03283         else {
03284             bp1= nu1->bp;
03285             a= nu1->pntsu*nu1->pntsv;
03286             while(a--) {
03287                 if( bp1->f1 & 1 ) {
03288                     if(*nu != NULL && *nu != nu1) {
03289                         *bp= NULL;
03290                         *bezt= NULL;
03291                         *nu= NULL;
03292                         return;
03293                     }
03294                     else if(*bezt || *bp) {
03295                         *bp= NULL;
03296                         *bezt= NULL;
03297                     }
03298                     else {
03299                         *bp= bp1;
03300                         *nu= nu1;
03301                     }
03302                 }
03303                 bp1++;
03304             }
03305         }
03306     }
03307 }
03308 
03309 /***************** set spline type operator *******************/
03310 
03311 static int convertspline(short type, Nurb *nu)
03312 {
03313     BezTriple *bezt;
03314     BPoint *bp;
03315     int a, c, nr;
03316 
03317     if(nu->type == CU_POLY) {
03318         if(type==CU_BEZIER) {               /* to Bezier with vecthandles  */
03319             nr= nu->pntsu;
03320             bezt =
03321                 (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
03322             nu->bezt= bezt;
03323             a= nr;
03324             bp= nu->bp;
03325             while(a--) {
03326                 copy_v3_v3(bezt->vec[1], bp->vec);
03327                 bezt->f1=bezt->f2=bezt->f3= bp->f1;
03328                 bezt->h1= bezt->h2= HD_VECT;
03329                 bezt->weight= bp->weight;
03330                 bezt->radius= bp->radius;
03331                 bp++;
03332                 bezt++;
03333             }
03334             MEM_freeN(nu->bp);
03335             nu->bp= NULL;
03336             nu->pntsu= nr;
03337             nu->type = CU_BEZIER;
03338             calchandlesNurb(nu);
03339         }
03340         else if(type==CU_NURBS) {
03341             nu->type = CU_NURBS;
03342             nu->orderu= 4;
03343             nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
03344             nurbs_knot_calc_u(nu);
03345             a= nu->pntsu*nu->pntsv;
03346             bp= nu->bp;
03347             while(a--) {
03348                 bp->vec[3]= 1.0;
03349                 bp++;
03350             }
03351         }
03352     }
03353     else if(nu->type == CU_BEZIER) {    /* Bezier */
03354         if(type==CU_POLY || type==CU_NURBS) {
03355             nr= 3*nu->pntsu;
03356             nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
03357             a= nu->pntsu;
03358             bezt= nu->bezt;
03359             bp= nu->bp;
03360             while(a--) {
03361                 if(type==CU_POLY && bezt->h1==HD_VECT && bezt->h2==HD_VECT) {
03362                     /* vector handle becomes 1 poly vertice */
03363                     copy_v3_v3(bp->vec, bezt->vec[1]);
03364                     bp->vec[3]= 1.0;
03365                     bp->f1= bezt->f2;
03366                     nr-= 2;
03367                     bp->radius= bezt->radius;
03368                     bp->weight= bezt->weight;
03369                     bp++;
03370                 }
03371                 else {
03372                     for(c=0;c<3;c++) {
03373                         copy_v3_v3(bp->vec, bezt->vec[c]);
03374                         bp->vec[3]= 1.0;
03375                         if(c==0) bp->f1= bezt->f1;
03376                         else if(c==1) bp->f1= bezt->f2;
03377                         else bp->f1= bezt->f3;
03378                         bp->radius= bezt->radius;
03379                         bp->weight= bezt->weight;
03380                         bp++;
03381                     }
03382                 }
03383                 bezt++;
03384             }
03385             MEM_freeN(nu->bezt); 
03386             nu->bezt= NULL;
03387             nu->pntsu= nr;
03388             nu->pntsv= 1;
03389             nu->orderu= 4;
03390             nu->orderv= 1;
03391             nu->type = type;
03392             if(nu->flagu & CU_NURB_CYCLIC) c= nu->orderu-1; 
03393             else c= 0;
03394             if(type== CU_NURBS) {
03395                 nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
03396                 nu->flagu |= CU_NURB_BEZIER;
03397                 nurbs_knot_calc_u(nu);
03398             }
03399         }
03400     }
03401     else if(nu->type == CU_NURBS) {
03402         if(type==CU_POLY) {
03403             nu->type = CU_POLY;
03404             if(nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
03405             nu->knotsu= NULL;
03406             if(nu->knotsv) MEM_freeN(nu->knotsv);
03407             nu->knotsv= NULL;
03408         }
03409         else if(type==CU_BEZIER) {      /* to Bezier */
03410             nr= nu->pntsu/3;
03411 
03412             if(nr<2) 
03413                 return 1;   /* conversion impossible */
03414             else {
03415                 bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
03416                 nu->bezt= bezt;
03417                 a= nr;
03418                 bp= nu->bp;
03419                 while(a--) {
03420                     copy_v3_v3(bezt->vec[0], bp->vec);
03421                     bezt->f1= bp->f1;
03422                     bp++;
03423                     copy_v3_v3(bezt->vec[1], bp->vec);
03424                     bezt->f2= bp->f1;
03425                     bp++;
03426                     copy_v3_v3(bezt->vec[2], bp->vec);
03427                     bezt->f3= bp->f1;
03428                     bezt->radius= bp->radius;
03429                     bezt->weight= bp->weight;
03430                     bp++;
03431                     bezt++;
03432                 }
03433                 MEM_freeN(nu->bp);
03434                 nu->bp= NULL;
03435                 MEM_freeN(nu->knotsu);
03436                 nu->knotsu= NULL;
03437                 nu->pntsu= nr;
03438                 nu->type = CU_BEZIER;
03439             }
03440         }
03441     }
03442 
03443     return 0;
03444 }
03445 
03446 void ED_nurb_set_spline_type(Nurb *nu, int type)
03447 {
03448     convertspline(type, nu);
03449 }
03450 
03451 static int set_spline_type_exec(bContext *C, wmOperator *op)
03452 {
03453     Object *obedit= CTX_data_edit_object(C);
03454     ListBase *editnurb= object_editcurve_get(obedit);
03455     Nurb *nu;
03456     int changed=0, type= RNA_enum_get(op->ptr, "type");
03457 
03458     if(type==CU_CARDINAL || type==CU_BSPLINE) {
03459         BKE_report(op->reports, RPT_ERROR, "Not implemented yet");
03460         return OPERATOR_CANCELLED;
03461     }
03462     
03463     for(nu= editnurb->first; nu; nu= nu->next) {
03464         if(isNurbsel(nu)) {
03465             if(convertspline(type, nu))
03466                 BKE_report(op->reports, RPT_ERROR, "No conversion possible");
03467             else
03468                 changed= 1;
03469         }
03470     }
03471 
03472     if(changed) {
03473         if(ED_curve_updateAnimPaths(obedit))
03474             WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
03475 
03476         DAG_id_tag_update(obedit->data, 0);
03477         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
03478 
03479         return OPERATOR_FINISHED;
03480     }
03481     else {
03482         return OPERATOR_CANCELLED;
03483     }
03484 }
03485 
03486 void CURVE_OT_spline_type_set(wmOperatorType *ot)
03487 {
03488     static EnumPropertyItem type_items[]= {
03489         {CU_POLY, "POLY", 0, "Poly", ""},
03490         {CU_BEZIER, "BEZIER", 0, "Bezier", ""},
03491 //      {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
03492 //      {CU_BSPLINE, "B_SPLINE", 0, "B-Spline", ""},
03493         {CU_NURBS, "NURBS", 0, "NURBS", ""},
03494         {0, NULL, 0, NULL, NULL}};
03495 
03496     /* identifiers */
03497     ot->name= "Set Spline Type";
03498     ot->description = "Set type of active spline";
03499     ot->idname= "CURVE_OT_spline_type_set";
03500     
03501     /* api callbacks */
03502     ot->exec= set_spline_type_exec;
03503     ot->invoke= WM_menu_invoke;
03504     ot->poll= ED_operator_editcurve;
03505     
03506     /* flags */
03507     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03508 
03509     /* properties */
03510     ot->prop= RNA_def_enum(ot->srna, "type", type_items, CU_POLY, "Type", "Spline type");
03511 }
03512 
03513 /***************** set handle type operator *******************/
03514 
03515 static int set_handle_type_exec(bContext *C, wmOperator *op)
03516 {
03517     Object *obedit= CTX_data_edit_object(C);
03518     ListBase *editnurb= object_editcurve_get(obedit);
03519 
03520     sethandlesNurb(editnurb, RNA_enum_get(op->ptr, "type"));
03521 
03522     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
03523     DAG_id_tag_update(obedit->data, 0);
03524 
03525     return OPERATOR_FINISHED;
03526 }
03527 
03528 void CURVE_OT_handle_type_set(wmOperatorType *ot)
03529 {
03530     /* keep in sync with graphkeys_handle_type_items */
03531     static EnumPropertyItem editcurve_handle_type_items[]= {
03532         {HD_AUTO, "AUTOMATIC", 0, "Automatic", ""},
03533         {HD_VECT, "VECTOR", 0, "Vector", ""},
03534         {5, "ALIGNED", 0, "Aligned", ""},
03535         {6, "FREE_ALIGN", 0, "Free", ""},
03536         {3, "TOGGLE_FREE_ALIGN", 0, "Toggle Free/Align", ""},
03537         {0, NULL, 0, NULL, NULL}};
03538 
03539     /* identifiers */
03540     ot->name= "Set Handle Type";
03541     ot->description = "Set type of handles for selected control points";
03542     ot->idname= "CURVE_OT_handle_type_set";
03543     
03544     /* api callbacks */
03545     ot->invoke= WM_menu_invoke;
03546     ot->exec= set_handle_type_exec;
03547     ot->poll= ED_operator_editcurve;
03548     
03549     /* flags */
03550     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03551 
03552     /* properties */
03553     ot->prop= RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
03554 }
03555 
03556 /***************** make segment operator **********************/
03557 
03558 /* ******************** SKINNING LOFTING!!! ******************** */
03559 
03560 static void switchdirection_knots(float *base, int tot)
03561 {
03562     float *fp1, *fp2, *tempf;
03563     int a;
03564     
03565     if(base==NULL || tot==0) return;
03566     
03567     /* reverse knots */
03568     a= tot;
03569     fp1= base;
03570     fp2= fp1+(a-1);
03571     a/= 2;
03572     while(fp1!=fp2 && a>0) {
03573         SWAP(float, *fp1, *fp2);
03574         a--;
03575         fp1++; 
03576         fp2--;
03577     }
03578     /* and make in increasing order again */
03579     a= tot;
03580     fp1= base;
03581     fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
03582     while(a--) {
03583         fp2[0]= fabs(fp1[1]-fp1[0]);
03584         fp1++;
03585         fp2++;
03586     }
03587 
03588     a= tot-1;
03589     fp1= base;
03590     fp2= tempf;
03591     fp1[0]= 0.0;
03592     fp1++;
03593     while(a--) {
03594         fp1[0]= fp1[-1]+fp2[0];
03595         fp1++;
03596         fp2++;
03597     }
03598     MEM_freeN(tempf);
03599 }
03600 
03601 static void rotate_direction_nurb(Nurb *nu)
03602 {
03603     BPoint *bp1, *bp2, *temp;
03604     int u, v;
03605     
03606     SWAP(short, nu->pntsu, nu->pntsv);
03607     SWAP(short, nu->orderu, nu->orderv);
03608     SWAP(short, nu->resolu, nu->resolv);
03609     SWAP(short, nu->flagu, nu->flagv);
03610     
03611     SWAP(float *, nu->knotsu, nu->knotsv);
03612     switchdirection_knots(nu->knotsv, KNOTSV(nu) );
03613     
03614     temp= MEM_dupallocN(nu->bp);
03615     bp1= nu->bp;
03616     for(v=0; v<nu->pntsv; v++) {
03617         for(u=0; u<nu->pntsu; u++, bp1++) {
03618             bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v;
03619             *bp1= *bp2;
03620         }
03621     }
03622 
03623     MEM_freeN(temp);
03624 }
03625 
03626 static int is_u_selected(Nurb *nu, int u)
03627 {
03628     BPoint *bp;
03629     int v;
03630     
03631     /* what about resolu == 2? */
03632     bp= nu->bp+u;
03633     for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) {
03634         if(v) if(bp->f1 & SELECT) return 1;
03635     }
03636     
03637     return 0;
03638 }
03639 
03640 typedef struct NurbSort {
03641     struct NurbSort *next, *prev;
03642     Nurb *nu;
03643     float vec[3];
03644 } NurbSort;
03645 
03646 static ListBase nsortbase= {NULL, NULL};
03647 /*  static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
03648 
03649 static void make_selection_list_nurb(ListBase *editnurb)
03650 {
03651     ListBase nbase= {NULL, NULL};
03652     NurbSort *nus, *nustest, *headdo, *taildo;
03653     Nurb *nu;
03654     BPoint *bp;
03655     float dist, headdist, taildist;
03656     int a;
03657     
03658     for(nu= editnurb->first; nu; nu= nu->next) {
03659         if( isNurbsel(nu) ) {
03660             
03661             nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort");
03662             BLI_addhead(&nbase, nus);
03663             nus->nu= nu;
03664             
03665             bp= nu->bp;
03666             a= nu->pntsu;
03667             while(a--) {
03668                 add_v3_v3(nus->vec, bp->vec);
03669                 bp++;
03670             }
03671             mul_v3_fl(nus->vec, 1.0f/(float)nu->pntsu);
03672             
03673             
03674         }
03675     }
03676 
03677     /* just add the first one */
03678     nus= nbase.first;
03679     BLI_remlink(&nbase, nus);
03680     BLI_addtail( &nsortbase, nus);
03681     
03682     /* now add, either at head or tail, the closest one */
03683     while(nbase.first) {
03684     
03685         headdist= taildist= 1.0e30;
03686         headdo= taildo= NULL;
03687 
03688         nustest= nbase.first;
03689         while(nustest) {
03690             dist= len_v3v3(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
03691 
03692             if(dist<headdist) {
03693                 headdist= dist;
03694                 headdo= nustest;
03695             }
03696             dist= len_v3v3(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
03697 
03698             if(dist<taildist) {
03699                 taildist= dist;
03700                 taildo= nustest;
03701             }
03702             nustest= nustest->next;
03703         }
03704         
03705         if(headdist<taildist) {
03706             BLI_remlink(&nbase, headdo);
03707             BLI_addhead(&nsortbase, headdo);
03708         }
03709         else {
03710             BLI_remlink(&nbase, taildo);
03711             BLI_addtail(&nsortbase, taildo);
03712         }
03713     }
03714 }
03715 
03716 static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu2)
03717 {
03718     BPoint *bp, *bp1, *bp2, *temp;
03719     float  len1, len2;
03720     int    origu, u, v;
03721     
03722     /* first nurbs will be changed to make u = resolu-1 selected */
03723     /* 2nd nurbs will be changed to make u = 0 selected */
03724 
03725     /* first nurbs: u = resolu-1 selected */
03726     
03727     if( is_u_selected(nu1, nu1->pntsu-1) );
03728     else {
03729         /* For 2D curves blender uses orderv=0. It doesn't make any sense mathematically. */
03730         /* but after rotating orderu=0 will be confusing. */
03731         if (nu1->orderv == 0) nu1->orderv= 1;
03732 
03733         rotate_direction_nurb(nu1);
03734         if( is_u_selected(nu1, nu1->pntsu-1) );
03735         else {
03736             rotate_direction_nurb(nu1);
03737             if( is_u_selected(nu1, nu1->pntsu-1) );
03738             else {
03739                 rotate_direction_nurb(nu1);
03740                 if( is_u_selected(nu1, nu1->pntsu-1) );
03741                 else {
03742                     /* rotate again, now its OK! */
03743                     if(nu1->pntsv!=1) rotate_direction_nurb(nu1);
03744                     return;
03745                 }
03746             }
03747         }
03748     }
03749     
03750     /* 2nd nurbs: u = 0 selected */
03751     if( is_u_selected(nu2, 0) );
03752     else {
03753         if (nu2->orderv == 0) nu2->orderv= 1;
03754         rotate_direction_nurb(nu2);
03755         if( is_u_selected(nu2, 0) );
03756         else {
03757             rotate_direction_nurb(nu2);
03758             if( is_u_selected(nu2, 0) );
03759             else {
03760                 rotate_direction_nurb(nu2);
03761                 if( is_u_selected(nu2, 0) );
03762                 else {
03763                     /* rotate again, now its OK! */
03764                     if(nu1->pntsu==1) rotate_direction_nurb(nu1);
03765                     if(nu2->pntsv!=1) rotate_direction_nurb(nu2);
03766                     return;
03767                 }
03768             }
03769         }
03770     }
03771     
03772     if( nu1->pntsv != nu2->pntsv ) {
03773         BKE_report(op->reports, RPT_ERROR, "Resolution doesn't match");
03774         return;
03775     }
03776     
03777     /* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */
03778     /* maybe we need a 'v' flip of nu2? */
03779     
03780     bp1= nu1->bp+nu1->pntsu-1;
03781     bp2= nu2->bp;
03782     len1= 0.0;
03783     
03784     for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) {
03785         len1+= len_v3v3(bp1->vec, bp2->vec);
03786     }
03787 
03788     bp1= nu1->bp + nu1->pntsu-1;
03789     bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1);
03790     len2= 0.0;
03791     
03792     for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) {
03793         len2+= len_v3v3(bp1->vec, bp2->vec);
03794     }
03795 
03796     /* merge */
03797     origu= nu1->pntsu;
03798     nu1->pntsu+= nu2->pntsu;
03799     if(nu1->orderu<3 && nu1->orderu<nu1->pntsu) nu1->orderu++;
03800     if(nu1->orderv<3 && nu1->orderv<nu1->pntsv) nu1->orderv++;
03801     temp= nu1->bp;
03802     nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP");
03803     
03804     bp= nu1->bp;
03805     bp1= temp;
03806     
03807     for(v=0; v<nu1->pntsv; v++) {
03808         
03809         /* switch direction? */
03810         if(len1<len2) bp2= nu2->bp + v*nu2->pntsu;
03811         else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu;
03812 
03813         for(u=0; u<nu1->pntsu; u++, bp++) {
03814             if(u<origu) {
03815                 *bp= *bp1; bp1++;
03816                 select_bpoint(bp, SELECT, 1, HIDDEN);
03817             }
03818             else {
03819                 *bp= *bp2; bp2++;
03820             }
03821         }
03822     }
03823 
03824     if(nu1->type == CU_NURBS) {
03825         /* merge knots */
03826         nurbs_knot_calc_u(nu1);
03827     
03828         /* make knots, for merged curved for example */
03829         nurbs_knot_calc_v(nu1);
03830     }
03831     
03832     MEM_freeN(temp);
03833     BLI_remlink(editnurb, nu2);
03834     freeNurb(nu2);
03835 }
03836 
03837 static int merge_nurb(bContext *C, wmOperator *op)
03838 {
03839     Object *obedit= CTX_data_edit_object(C);
03840     ListBase *editnurb= object_editcurve_get(obedit);
03841     NurbSort *nus1, *nus2;
03842     int ok= 1;
03843     
03844     make_selection_list_nurb(editnurb);
03845     
03846     if(nsortbase.first == nsortbase.last) {
03847         BLI_freelistN(&nsortbase);
03848         BKE_report(op->reports, RPT_ERROR, "Too few selections to merge");
03849         return OPERATOR_CANCELLED;
03850     }
03851     
03852     nus1= nsortbase.first;
03853     nus2= nus1->next;
03854 
03855     /* resolution match, to avoid uv rotations */
03856     if(nus1->nu->pntsv==1) {
03857         if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv);
03858         else ok= 0;
03859     }
03860     else if(nus2->nu->pntsv==1) {
03861         if(nus2->nu->pntsu==nus1->nu->pntsu || nus2->nu->pntsu==nus1->nu->pntsv);
03862         else ok= 0;
03863     }
03864     else if( nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsv==nus2->nu->pntsv);
03865     else if( nus1->nu->pntsu==nus2->nu->pntsv || nus1->nu->pntsv==nus2->nu->pntsu);
03866     else {
03867         ok= 0;
03868     }
03869     
03870     if(ok==0) {
03871         BKE_report(op->reports, RPT_ERROR, "Resolution doesn't match");
03872         BLI_freelistN(&nsortbase);
03873         return OPERATOR_CANCELLED;
03874     }
03875 
03876     while(nus2) {
03877         merge_2_nurb(op, editnurb, nus1->nu, nus2->nu);
03878         nus2= nus2->next;
03879     }
03880     
03881     BLI_freelistN(&nsortbase);
03882     
03883     set_actNurb(obedit, NULL);
03884 
03885     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
03886     DAG_id_tag_update(obedit->data, 0);
03887     
03888     return OPERATOR_FINISHED;
03889 }
03890 
03891 static int make_segment_exec(bContext *C, wmOperator *op)
03892 {
03893     /* joins 2 curves */
03894     Object *obedit= CTX_data_edit_object(C);
03895     Curve *cu= obedit->data;
03896     ListBase *nubase= object_editcurve_get(obedit);
03897     Nurb *nu, *nu1=NULL, *nu2=NULL;
03898     BPoint *bp;
03899     float *fp, offset;
03900     int a, ok= 0;
03901 
03902     /* first decide if this is a surface merge! */
03903     if(obedit->type==OB_SURF) nu= nubase->first;
03904     else nu= NULL;
03905     
03906     while(nu) {
03907         if( isNurbsel(nu) ) {
03908         
03909             if(nu->pntsu>1 && nu->pntsv>1) break;
03910             if(isNurbsel_count(cu, nu)>1) break;
03911             if(isNurbsel_count(cu, nu)==1) {
03912                 /* only 1 selected, not first or last, a little complex, but intuitive */
03913                 if(nu->pntsv==1) {
03914                     if( (nu->bp->f1 & SELECT) || ((nu->bp+nu->pntsu-1)->f1 & SELECT));
03915                     else break;
03916                 }
03917             }
03918         }
03919         nu= nu->next;
03920     }
03921 
03922     if(nu)
03923         return merge_nurb(C, op);
03924     
03925     /* find both nurbs and points, nu1 will be put behind nu2 */
03926     for(nu= nubase->first; nu; nu= nu->next) {
03927         if(nu->pntsu == 1)
03928             nu->flagu&= ~CU_NURB_CYCLIC;
03929 
03930         if((nu->flagu & CU_NURB_CYCLIC)==0) {    /* not cyclic */
03931             if(nu->type == CU_BEZIER) {
03932                 if(nu1==NULL) {
03933                     if( BEZSELECTED_HIDDENHANDLES(cu, nu->bezt) ) nu1= nu;
03934                     else {
03935                         if( BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu-1])) ) {
03936                             nu1= nu;
03937                             switchdirectionNurb(nu);
03938                             keyData_switchDirectionNurb(cu, nu);
03939                         }
03940                     }
03941                 }
03942                 else if(nu2==NULL) {
03943                     if( BEZSELECTED_HIDDENHANDLES(cu, nu->bezt) ) {
03944                         nu2= nu;
03945                         switchdirectionNurb(nu);
03946                         keyData_switchDirectionNurb(cu, nu);
03947                     }
03948                     else {
03949                         if( BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu-1])) ) {
03950                             nu2= nu;
03951                         }
03952                     }
03953                 }
03954                 else break;
03955             }
03956             else if(nu->pntsv==1) {
03957                 bp= nu->bp;
03958                 if(nu1==NULL) {
03959                     if( bp->f1 & SELECT) nu1= nu;
03960                     else {
03961                         bp= bp+(nu->pntsu-1);
03962                         if( bp->f1 & SELECT ) {
03963                             nu1= nu;
03964                             switchdirectionNurb(nu);
03965                             keyData_switchDirectionNurb(cu, nu);
03966                         }
03967                     }
03968                 }
03969                 else if(nu2==NULL) {
03970                     if( bp->f1 & SELECT ) {
03971                         nu2= nu;
03972                         switchdirectionNurb(nu);
03973                         keyData_switchDirectionNurb(cu, nu);
03974                     }
03975                     else {
03976                         bp= bp+(nu->pntsu-1);
03977                         if( bp->f1 & SELECT ) {
03978                             nu2= nu;
03979                         }
03980                     }
03981                 }
03982                 else break;
03983             }
03984         }
03985     }
03986 
03987     if((nu1 && nu2) && (nu1!=nu2)) {
03988         if( nu1->type==nu2->type) {
03989             if(nu1->type == CU_BEZIER) {
03990                 BezTriple *bezt =
03991                     (BezTriple*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BezTriple), "addsegmentN");
03992                 ED_curve_beztcpy(cu->editnurb, bezt, nu2->bezt, nu2->pntsu);
03993                 ED_curve_beztcpy(cu->editnurb, bezt+nu2->pntsu, nu1->bezt, nu1->pntsu);
03994 
03995                 MEM_freeN(nu1->bezt);
03996                 nu1->bezt= bezt;
03997                 nu1->pntsu+= nu2->pntsu;
03998                 BLI_remlink(nubase, nu2);
03999                 freeNurb(nu2); nu2= NULL;
04000                 calchandlesNurb(nu1);
04001             }
04002             else {
04003                 bp =
04004                     (BPoint*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BPoint), "addsegmentN2");
04005                 ED_curve_bpcpy(cu->editnurb, bp, nu2->bp, nu2->pntsu);
04006                 ED_curve_bpcpy(cu->editnurb, bp+nu2->pntsu, nu1->bp, nu1->pntsu);
04007                 MEM_freeN(nu1->bp);
04008                 nu1->bp= bp;
04009 
04010                 a= nu1->pntsu+nu1->orderu;
04011 
04012                 nu1->pntsu+= nu2->pntsu;
04013                 BLI_remlink(nubase, nu2);
04014 
04015                 /* now join the knots */
04016                 if(nu1->type == CU_NURBS) {
04017                     if(nu1->knotsu==NULL) {
04018                         nurbs_knot_calc_u(nu1);
04019                     }
04020                     else {
04021                         fp= MEM_mallocN(sizeof(float)*KNOTSU(nu1), "addsegment3");
04022                         memcpy(fp, nu1->knotsu, sizeof(float)*a);
04023                         MEM_freeN(nu1->knotsu);
04024                         nu1->knotsu= fp;
04025                         
04026                         
04027                         offset= nu1->knotsu[a-1] + 1.0f;
04028                         fp= nu1->knotsu+a;
04029                         for(a=0; a<nu2->pntsu; a++, fp++) {
04030                             if(nu2->knotsu) 
04031                                 *fp= offset+nu2->knotsu[a+1];
04032                             else 
04033                                 *fp = offset;
04034                         }
04035                     }
04036                 }
04037                 freeNurb(nu2); nu2= NULL;
04038             }
04039 
04040             set_actNurb(obedit, nu1);   /* for selected */
04041             ok= 1;
04042         }
04043     } else if(nu1 && !nu2) {
04044         if(!(nu1->flagu & CU_NURB_CYCLIC) && nu1->pntsu>1) {
04045             if (nu1->type == CU_BEZIER && BEZSELECTED_HIDDENHANDLES(cu, nu1->bezt) &&
04046                 BEZSELECTED_HIDDENHANDLES(cu, nu1->bezt+(nu1->pntsu-1))) {
04047                 nu1->flagu|= CU_NURB_CYCLIC;
04048                 calchandlesNurb(nu1);
04049                 ok= 1;
04050             } else if (nu1->type == CU_NURBS && nu1->bp->f1&SELECT && (nu1->bp+(nu1->pntsu-1))->f1&SELECT) {
04051                 nu1->flagu|= CU_NURB_CYCLIC;
04052                 nurbs_knot_calc_u(nu1);
04053                 ok= 1;
04054             }
04055         }
04056     }
04057 
04058     if(!ok) {
04059         BKE_report(op->reports, RPT_ERROR, "Can't make segment");
04060         return OPERATOR_CANCELLED;
04061     }
04062 
04063     if(ED_curve_updateAnimPaths(obedit))
04064         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
04065 
04066     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04067     DAG_id_tag_update(obedit->data, 0);
04068 
04069     return OPERATOR_FINISHED;
04070 }
04071 
04072 void CURVE_OT_make_segment(wmOperatorType *ot)
04073 {
04074     /* identifiers */
04075     ot->name= "Make Segment";
04076     ot->idname= "CURVE_OT_make_segment";
04077     
04078     /* api callbacks */
04079     ot->exec= make_segment_exec;
04080     ot->poll= ED_operator_editsurfcurve;
04081 
04082     /* flags */
04083     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04084 }
04085 
04086 /***************** pick select from 3d view **********************/
04087 
04088 int mouse_nurb(bContext *C, const int mval[2], int extend)
04089 {
04090     Object *obedit= CTX_data_edit_object(C); 
04091     Curve *cu= obedit->data;
04092     ListBase *editnurb= object_editcurve_get(obedit);
04093     ViewContext vc;
04094     Nurb *nu;
04095     BezTriple *bezt=NULL;
04096     BPoint *bp=NULL;
04097     int location[2];
04098     short hand;
04099     
04100     view3d_operator_needs_opengl(C);
04101     view3d_set_viewcontext(C, &vc);
04102     
04103     location[0]= mval[0];
04104     location[1]= mval[1];
04105     hand= findnearestNurbvert(&vc, 1, location, &nu, &bezt, &bp);
04106 
04107     if(bezt || bp) {
04108         if(extend==0) {
04109         
04110             setflagsNurb(editnurb, 0);
04111 
04112             if(bezt) {
04113 
04114                 if(hand==1) {
04115                     select_beztriple(bezt, SELECT, 1, HIDDEN);
04116                     cu->lastsel= bezt;
04117                 } else {
04118                     if(hand==0) bezt->f1|= SELECT;
04119                     else bezt->f3|= SELECT;
04120 
04121                     cu->lastsel= NULL;
04122                 }
04123             }
04124             else {
04125                 cu->lastsel= bp;
04126                 select_bpoint(bp, SELECT, 1, HIDDEN);
04127             }
04128 
04129         }
04130         else {
04131             if(bezt) {
04132                 if(hand==1) {
04133                     if(bezt->f2 & SELECT) {
04134                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
04135                         if (bezt == cu->lastsel) cu->lastsel = NULL;
04136                     } else {
04137                         select_beztriple(bezt, SELECT, 1, HIDDEN);
04138                         cu->lastsel= bezt;
04139                     }
04140                 } else if(hand==0) {
04141                     bezt->f1 ^= SELECT;
04142                 } else {
04143                     bezt->f3 ^= SELECT;
04144                 }
04145             }
04146             else {
04147                 if(bp->f1 & SELECT) {
04148                     select_bpoint(bp, DESELECT, 1, HIDDEN);
04149                     if (cu->lastsel == bp) cu->lastsel = NULL;
04150                 } else {
04151                     select_bpoint(bp, SELECT, 1, HIDDEN);
04152                     cu->lastsel= bp;
04153                 }
04154             }
04155 
04156         }
04157 
04158         if(nu!=get_actNurb(obedit))
04159             set_actNurb(obedit, nu);
04160 
04161         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
04162 
04163         return 1;
04164     }
04165     
04166     return 0;
04167 }
04168 
04169 /******************** spin operator ***********************/
04170 
04171 /* 'cent' is in object space and 'dvec' in worldspace.
04172  */
04173 static int spin_nurb(float viewmat[][4], Object *obedit, float *axis, float *cent)
04174 {
04175     Curve *cu= (Curve*)obedit->data;
04176     ListBase *editnurb= object_editcurve_get(obedit);
04177     Nurb *nu;
04178     float si,phi,n[3],q[4],cmat[3][3],tmat[3][3],imat[3][3];
04179     float bmat[3][3], rotmat[3][3], scalemat1[3][3], scalemat2[3][3];
04180     float persmat[3][3], persinv[3][3];
04181     short a,ok, changed= 0;
04182 
04183     copy_m3_m4(persmat, viewmat);
04184     invert_m3_m3(persinv, persmat);
04185 
04186     /* imat and center and size */
04187     copy_m3_m4(bmat, obedit->obmat);
04188     invert_m3_m3(imat, bmat);
04189     
04190     normalize_v3_v3(n, axis);
04191     
04192     phi= M_PI/8.0;
04193     q[0]= cos(phi);
04194     si= sin(phi);
04195     q[1]= n[0]*si;
04196     q[2]= n[1]*si;
04197     q[3]= n[2]*si;
04198     quat_to_mat3( cmat,q);
04199     mul_m3_m3m3(tmat, cmat, bmat);
04200     mul_m3_m3m3(rotmat, imat, tmat);
04201 
04202     unit_m3(scalemat1);
04203     scalemat1[0][0]= M_SQRT2;
04204     scalemat1[1][1]= M_SQRT2;
04205 
04206     mul_m3_m3m3(tmat,persmat,bmat);
04207     mul_m3_m3m3(cmat,scalemat1,tmat);
04208     mul_m3_m3m3(tmat,persinv,cmat);
04209     mul_m3_m3m3(scalemat1,imat,tmat);
04210 
04211     unit_m3(scalemat2);
04212     scalemat2[0][0]/= (float)M_SQRT2;
04213     scalemat2[1][1]/= (float)M_SQRT2;
04214 
04215     mul_m3_m3m3(tmat,persmat,bmat);
04216     mul_m3_m3m3(cmat,scalemat2,tmat);
04217     mul_m3_m3m3(tmat,persinv,cmat);
04218     mul_m3_m3m3(scalemat2,imat,tmat);
04219 
04220     ok= 1;
04221 
04222     for(a=0;a<7;a++) {
04223         ok= extrudeflagNurb(cu->editnurb, 1);
04224 
04225         if(ok==0)
04226             return changed;
04227 
04228         changed= 1;
04229 
04230         rotateflagNurb(editnurb, SELECT, cent, rotmat);
04231 
04232         if( (a & SELECT)==0 ) {
04233             rotateflagNurb(editnurb, SELECT, cent, scalemat1);
04234             weightflagNurb(editnurb, SELECT, 0.25*M_SQRT2);
04235         }
04236         else {
04237             rotateflagNurb(editnurb, SELECT, cent, scalemat2);
04238             weightflagNurb(editnurb, SELECT, 4.0/M_SQRT2);
04239         }
04240     }
04241 
04242     if(ok) {
04243         for(nu= editnurb->first; nu; nu= nu->next) {
04244             if(isNurbsel(nu)) {
04245                 nu->orderv= 4;
04246                 nu->flagv |= CU_NURB_CYCLIC;
04247                 nurbs_knot_calc_v(nu);
04248             }
04249         }
04250     }
04251 
04252     return changed;
04253 }
04254 
04255 static int spin_exec(bContext *C, wmOperator *op)
04256 {
04257     Object *obedit= CTX_data_edit_object(C);
04258     RegionView3D *rv3d= ED_view3d_context_rv3d(C);
04259     float cent[3], axis[3], viewmat[4][4];
04260     
04261     RNA_float_get_array(op->ptr, "center", cent);
04262     RNA_float_get_array(op->ptr, "axis", axis);
04263     
04264     invert_m4_m4(obedit->imat, obedit->obmat);
04265     mul_m4_v3(obedit->imat, cent);
04266     
04267     if(rv3d)
04268         copy_m4_m4(viewmat, rv3d->viewmat);
04269     else
04270         unit_m4(viewmat);
04271     
04272     if(!spin_nurb(viewmat, obedit, axis, cent)) {
04273         BKE_report(op->reports, RPT_ERROR, "Can't spin");
04274         return OPERATOR_CANCELLED;
04275     }
04276 
04277     if(ED_curve_updateAnimPaths(obedit))
04278         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
04279 
04280     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04281     DAG_id_tag_update(obedit->data, 0);
04282 
04283     return OPERATOR_FINISHED;
04284 }
04285 
04286 static int spin_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
04287 {
04288     Scene *scene = CTX_data_scene(C);
04289     View3D *v3d = CTX_wm_view3d(C);
04290     RegionView3D *rv3d= ED_view3d_context_rv3d(C);
04291     float axis[3]= {0.0f, 0.0f, 1.0f};
04292     
04293     if(rv3d)
04294         copy_v3_v3(axis, rv3d->viewinv[2]);
04295     
04296     RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
04297     RNA_float_set_array(op->ptr, "axis", axis);
04298     
04299     return spin_exec(C, op);
04300 }
04301 
04302 void CURVE_OT_spin(wmOperatorType *ot)
04303 {
04304     /* identifiers */
04305     ot->name= "Spin";
04306     ot->idname= "CURVE_OT_spin";
04307     
04308     /* api callbacks */
04309     ot->exec= spin_exec;
04310     ot->invoke = spin_invoke;
04311     ot->poll= ED_operator_editsurf;
04312 
04313     /* flags */
04314     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04315     
04316     RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
04317     RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
04318 }
04319 
04320 /***************** add vertex operator **********************/
04321 
04322 static int addvert_Nurb(bContext *C, short mode, float location[3])
04323 {
04324     Object *obedit= CTX_data_edit_object(C);
04325     Curve *cu= (Curve*)obedit->data;
04326     EditNurb *editnurb= cu->editnurb;
04327     Nurb *nu, *newnu= NULL;
04328     BezTriple *bezt, *newbezt = NULL;
04329     BPoint *bp, *newbp = NULL;
04330     float imat[4][4], temp[3];
04331     int ok= 0;
04332 
04333     invert_m4_m4(imat, obedit->obmat);
04334 
04335     findselectedNurbvert(&editnurb->nurbs, &nu, &bezt, &bp);
04336 
04337     if ((nu == NULL) || (nu->type==CU_BEZIER && bezt==NULL) || (nu->type!=CU_BEZIER && bp==NULL)) {
04338         if(mode!='e') {
04339             if(cu->actnu >= 0)
04340                 nu= BLI_findlink(&editnurb->nurbs, cu->actnu);
04341 
04342             if(!nu || nu->type==CU_BEZIER) {
04343                 newbezt= (BezTriple*)MEM_callocN(sizeof(BezTriple), "addvert_Nurb");
04344                 newbezt->radius= 1;
04345                 newbezt->alfa= 0;
04346                 BEZ_SEL(newbezt);
04347                 newbezt->h2= newbezt->h1= HD_AUTO;
04348 
04349                 newnu= (Nurb*)MEM_callocN(sizeof(Nurb), "addvert_Nurb newnu");
04350                 if(!nu) {
04351                     /* no selected sement -- create new one which is BEZIER tpye
04352                        type couldn't be determined from Curve bt could be changed
04353                        in the future, so shouldn't make much headache */
04354                     newnu->type= CU_BEZIER;
04355                     newnu->resolu= cu->resolu;
04356                     newnu->flag |= CU_SMOOTH;
04357                 } else memcpy(newnu, nu, sizeof(Nurb));
04358 
04359                 BLI_addtail(&editnurb->nurbs, newnu);
04360                 set_actNurb(obedit, newnu);
04361                 newnu->bezt= newbezt;
04362                 newnu->pntsu= 1;
04363 
04364                 temp[0] = 1;
04365                 temp[1] = 0;
04366                 temp[2] = 0;
04367 
04368                 copy_v3_v3(newbezt->vec[1], location);
04369                 sub_v3_v3v3(newbezt->vec[0], newbezt->vec[1], temp);
04370                 add_v3_v3v3(newbezt->vec[2], newbezt->vec[1], temp);
04371 
04372                 mul_m4_v3(imat, newbezt->vec[0]);
04373                 mul_m4_v3(imat, newbezt->vec[1]);
04374                 mul_m4_v3(imat, newbezt->vec[2]);
04375 
04376                 ok= 1;
04377                 nu= newnu;
04378             } else if(nu->pntsv == 1) {
04379                 newbp= (BPoint*)MEM_callocN(sizeof(BPoint), "addvert_Nurb5");
04380                 newbp->radius= 1;
04381                 newbp->alfa= 0;
04382                 newbp->f1|= SELECT;
04383                 cu->lastsel= newbp;
04384 
04385                 newnu= (Nurb*)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
04386                 memcpy(newnu, nu, sizeof(Nurb));
04387                 BLI_addtail(&editnurb->nurbs, newnu);
04388                 set_actNurb(obedit, newnu);
04389                 newnu->bp= newbp;
04390                 newnu->orderu= 2;
04391                 newnu->pntsu= 1;
04392 
04393                 mul_v3_m4v3(newbp->vec, imat, location);
04394                 newbp->vec[3]= 1.0;
04395 
04396                 newnu->knotsu= newnu->knotsv= NULL;
04397                 nurbs_knot_calc_u(newnu);
04398 
04399                 ok= 1;
04400                 nu= newnu;
04401             }
04402 
04403         }
04404 
04405         if(!ok)
04406             return OPERATOR_CANCELLED;
04407     }
04408 
04409     if(!ok && nu->type == CU_BEZIER) {
04410         /* which bezpoint? */
04411         if(bezt== (nu->bezt+nu->pntsu-1)) {  /* last */
04412             BEZ_DESEL(bezt);
04413             newbezt =
04414                 (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
04415             ED_curve_beztcpy(editnurb, newbezt, nu->bezt, nu->pntsu);
04416             *(newbezt+nu->pntsu)= *bezt;
04417             copy_v3_v3(temp, bezt->vec[1]);
04418             MEM_freeN(nu->bezt);
04419             nu->bezt= newbezt;
04420             newbezt+= nu->pntsu;
04421             BEZ_SEL(newbezt);
04422             cu->lastsel= newbezt;
04423             newbezt->h2= newbezt->h1;
04424             bezt= nu->bezt+nu->pntsu-1;
04425             ok= 1;
04426         }
04427         else if(bezt== nu->bezt) {   /* first */
04428             BEZ_DESEL(bezt);
04429             newbezt =
04430                 (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
04431             ED_curve_beztcpy(editnurb, newbezt+1, bezt, nu->pntsu);
04432             *newbezt= *bezt;
04433             BEZ_SEL(newbezt);
04434             cu->lastsel= newbezt;
04435             newbezt->h2= newbezt->h1;
04436             copy_v3_v3(temp, bezt->vec[1]);
04437             MEM_freeN(nu->bezt);
04438             nu->bezt= newbezt;
04439             bezt= newbezt+1;
04440             ok= 1;
04441         }
04442         else if(mode!='e') {
04443             BEZ_DESEL(bezt);
04444             newbezt= (BezTriple*)MEM_callocN(sizeof(BezTriple), "addvert_Nurb");
04445             *newbezt= *bezt;
04446             BEZ_SEL(newbezt);
04447             newbezt->h2= newbezt->h1;
04448             copy_v3_v3(temp, bezt->vec[1]);
04449 
04450             newnu= (Nurb*)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
04451             memcpy(newnu, nu, sizeof(Nurb));
04452             BLI_addtail(&editnurb->nurbs, newnu);
04453             set_actNurb(obedit, newnu);
04454             newnu->bezt= newbezt;
04455             newnu->pntsu= 1;
04456 
04457             cu->lastsel= newbezt;
04458 
04459             bezt= newbezt;
04460             ok= 1;
04461         }
04462         else bezt= NULL;
04463 
04464         if(bezt) {
04465             if(!newnu) nu->pntsu++;
04466 
04467             if(mode=='e') {
04468                 copy_v3_v3(newbezt->vec[0], bezt->vec[0]);
04469                 copy_v3_v3(newbezt->vec[1], bezt->vec[1]);
04470                 copy_v3_v3(newbezt->vec[2], bezt->vec[2]);
04471             }
04472             else {
04473                 mul_v3_m4v3(newbezt->vec[1], imat, location);
04474                 sub_v3_v3v3(temp, newbezt->vec[1],temp);
04475                 add_v3_v3v3(newbezt->vec[0], bezt->vec[0],temp);
04476                 add_v3_v3v3(newbezt->vec[2], bezt->vec[2],temp);
04477 
04478                 if(newnu) calchandlesNurb(newnu);
04479                 else calchandlesNurb(nu);
04480             }
04481         }
04482     }
04483     else if(!ok && nu->pntsv==1) {
04484         /* which b-point? */
04485         if(bp== (nu->bp+nu->pntsu-1)) {  /* last */
04486             bp->f1= 0;
04487             newbp =
04488                 (BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb4");
04489             ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
04490             *(newbp+nu->pntsu)= *bp;
04491             MEM_freeN(nu->bp);
04492             nu->bp= newbp;
04493             newbp+= nu->pntsu;
04494             newbp->f1|= SELECT;
04495             cu->lastsel= newbp;
04496             bp= newbp - 1;
04497             ok= 1;
04498         }
04499         else if(bp== nu->bp) {   /* first */
04500             bp->f1= 0;
04501             newbp =
04502                 (BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb3");
04503             ED_curve_bpcpy(editnurb, newbp+1, bp, nu->pntsu);
04504             *newbp= *bp;
04505             newbp->f1|= SELECT;
04506             cu->lastsel= newbp;
04507             MEM_freeN(nu->bp);
04508             nu->bp= newbp;
04509             bp= newbp + 1;
04510             ok= 1;
04511         }
04512         else if(mode!='e') {
04513             bp->f1= 0;
04514             newbp= (BPoint*)MEM_callocN(sizeof(BPoint), "addvert_Nurb5");
04515             *newbp= *bp;
04516             newbp->f1|= SELECT;
04517             cu->lastsel= newbp;
04518 
04519             newnu= (Nurb*)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
04520             memcpy(newnu, nu, sizeof(Nurb));
04521             BLI_addtail(&editnurb->nurbs, newnu);
04522             set_actNurb(obedit, newnu);
04523             newnu->bp= newbp;
04524             newnu->orderu= 2;
04525             newnu->pntsu= 1;
04526             newnu->knotsu= newnu->knotsv= NULL;
04527 
04528             bp= newbp;
04529             ok= 1;
04530         }
04531         else bp= NULL;
04532 
04533         if(bp) {
04534             if(mode=='e') {
04535                 copy_v3_v3(newbp->vec, bp->vec);
04536             }
04537             else {
04538                 mul_v3_m4v3(newbp->vec, imat, location);
04539                 newbp->vec[3]= 1.0;
04540 
04541                 if(!newnu && nu->orderu<4 && nu->orderu<=nu->pntsu)
04542                     nu->orderu++;
04543             }
04544 
04545             if(!newnu) {
04546                 nu->pntsu++;
04547                 nurbs_knot_calc_u(nu);
04548             } else nurbs_knot_calc_u(newnu);
04549         }
04550     }
04551 
04552     if(ok) {
04553         test2DNurb(nu);
04554 
04555         if(ED_curve_updateAnimPaths(obedit))
04556             WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
04557 
04558         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04559         DAG_id_tag_update(obedit->data, 0);
04560 
04561         return OPERATOR_FINISHED;
04562     }
04563 
04564     return OPERATOR_CANCELLED;
04565 }
04566 
04567 static int add_vertex_exec(bContext *C, wmOperator *op)
04568 {
04569     float location[3];
04570 
04571     RNA_float_get_array(op->ptr, "location", location);
04572     return addvert_Nurb(C, 0, location);
04573 }
04574 
04575 static int add_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event)
04576 {
04577     RegionView3D *rv3d= CTX_wm_region_view3d(C);
04578 
04579     if(rv3d && !RNA_struct_property_is_set(op->ptr, "location")) {
04580         Curve *cu;
04581         ViewContext vc;
04582         float location[3];
04583 
04584         Nurb *nu;
04585         BezTriple *bezt;
04586         BPoint *bp;
04587 
04588         view3d_set_viewcontext(C, &vc);
04589 
04590         cu= vc.obedit->data;
04591 
04592         findselectedNurbvert(&cu->editnurb->nurbs, &nu, &bezt, &bp);
04593 
04594         if(bezt) {
04595             mul_v3_m4v3(location, vc.obedit->obmat, bezt->vec[1]);
04596         }
04597         else if (bp) {
04598             mul_v3_m4v3(location, vc.obedit->obmat, bp->vec);
04599         }
04600         else {
04601             copy_v3_v3(location, give_cursor(vc.scene, vc.v3d));
04602         }
04603 
04604         view3d_get_view_aligned_coordinate(&vc, location, event->mval, TRUE);
04605         RNA_float_set_array(op->ptr, "location", location);
04606     }
04607 
04608     return add_vertex_exec(C, op);
04609 }
04610 
04611 void CURVE_OT_vertex_add(wmOperatorType *ot)
04612 {
04613     /* identifiers */
04614     ot->name= "Add Vertex";
04615     ot->idname= "CURVE_OT_vertex_add";
04616     
04617     /* api callbacks */
04618     ot->exec= add_vertex_exec;
04619     ot->invoke= add_vertex_invoke;
04620     ot->poll= ED_operator_editcurve;
04621 
04622     /* flags */
04623     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04624 
04625     /* properties */
04626     RNA_def_float_vector_xyz(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "Location to add new vertex at", -1e4, 1e4);
04627 }
04628 
04629 /***************** extrude operator **********************/
04630 
04631 static int extrude_exec(bContext *C, wmOperator *UNUSED(op))
04632 {
04633     Object *obedit= CTX_data_edit_object(C);
04634     Curve *cu= obedit->data;
04635     EditNurb *editnurb= cu->editnurb;
04636     Nurb *nu;
04637     
04638     /* first test: curve? */
04639     for(nu= editnurb->nurbs.first; nu; nu= nu->next)
04640         if(nu->pntsv==1 && isNurbsel_count(cu, nu)==1)
04641             break;
04642 
04643     if(obedit->type==OB_CURVE || nu) {
04644         addvert_Nurb(C, 'e', NULL);
04645     }
04646     else {
04647         if(extrudeflagNurb(editnurb, 1)) { /* '1'= flag */
04648             if(ED_curve_updateAnimPaths(obedit))
04649                 WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
04650 
04651             WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04652             DAG_id_tag_update(obedit->data, 0);
04653         }
04654     }
04655 
04656     return OPERATOR_FINISHED;
04657 }
04658 
04659 void CURVE_OT_extrude(wmOperatorType *ot)
04660 {
04661     /* identifiers */
04662     ot->name= "Extrude";
04663     ot->description = "Extrude selected control point(s) and move";
04664     ot->idname= "CURVE_OT_extrude";
04665     
04666     /* api callbacks */
04667     ot->exec= extrude_exec;
04668     ot->poll= ED_operator_editsurfcurve;
04669 
04670     /* flags */
04671     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04672 
04673     /* to give to transform */
04674     RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
04675 }
04676 
04677 /***************** make cyclic operator **********************/
04678 
04679 static int toggle_cyclic_exec(bContext *C, wmOperator *op)
04680 {
04681     Object *obedit= CTX_data_edit_object(C);
04682     Curve *cu= obedit->data;
04683     ListBase *editnurb= object_editcurve_get(obedit);
04684     Nurb *nu;
04685     BezTriple *bezt;
04686     BPoint *bp;
04687     int a, direction= RNA_enum_get(op->ptr, "direction");
04688 
04689     for(nu= editnurb->first; nu; nu= nu->next) {
04690         if( nu->pntsu>1 || nu->pntsv>1) {
04691             if(nu->type == CU_POLY) {
04692                 a= nu->pntsu;
04693                 bp= nu->bp;
04694                 while(a--) {
04695                     if( bp->f1 & SELECT ) {
04696                         nu->flagu ^= CU_NURB_CYCLIC;
04697                         break;
04698                     }
04699                     bp++;
04700                 }
04701             }
04702             else if(nu->type == CU_BEZIER) {
04703                 a= nu->pntsu;
04704                 bezt= nu->bezt;
04705                 while(a--) {
04706                     if( BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
04707                         nu->flagu ^= CU_NURB_CYCLIC;
04708                         break;
04709                     }
04710                     bezt++;
04711                 }
04712                 calchandlesNurb(nu);
04713             }
04714             else if(nu->pntsv==1 && nu->type == CU_NURBS) {
04715                 if (nu->knotsu) { /* if check_valid_nurb_u fails the knotsu can be NULL */
04716                     a= nu->pntsu;
04717                     bp= nu->bp;
04718                     while(a--) {
04719                         if( bp->f1 & SELECT ) {
04720                             nu->flagu ^= CU_NURB_CYCLIC;
04721                             nurbs_knot_calc_u(nu);  /* 1==u  type is ignored for cyclic curves */
04722                             break;
04723                         }
04724                         bp++;
04725                     }
04726                 }
04727             }
04728             else if(nu->type==CU_NURBS) {
04729                 a= nu->pntsu*nu->pntsv;
04730                 bp= nu->bp;
04731                 while(a--) {
04732     
04733                     if( bp->f1 & SELECT) {
04734                         if(direction==0 && nu->pntsu>1) {
04735                             nu->flagu ^= CU_NURB_CYCLIC;
04736                             nurbs_knot_calc_u(nu);   /* 1==u  type is ignored for cyclic curves */
04737                         }
04738                         if(direction==1 && nu->pntsv>1) {
04739                             nu->flagv ^= CU_NURB_CYCLIC;
04740                             nurbs_knot_calc_v(nu);   /* 2==v  type is ignored for cyclic curves */
04741                         }
04742                         break;
04743                     }
04744                     bp++;
04745                 }
04746     
04747             }
04748         }
04749     }
04750 
04751     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
04752     DAG_id_tag_update(obedit->data, 0);
04753 
04754     return OPERATOR_FINISHED;
04755 }
04756 
04757 static int toggle_cyclic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
04758 {
04759     Object *obedit= CTX_data_edit_object(C);
04760     ListBase *editnurb= object_editcurve_get(obedit);
04761     uiPopupMenu *pup;
04762     uiLayout *layout;
04763     Nurb *nu;
04764 
04765     if(obedit->type == OB_SURF) {
04766         for(nu= editnurb->first; nu; nu= nu->next) {
04767             if(nu->pntsu>1 || nu->pntsv>1) {
04768                 if(nu->type==CU_NURBS) {
04769                     pup= uiPupMenuBegin(C, "Direction", ICON_NONE);
04770                     layout= uiPupMenuLayout(pup);
04771                     uiItemsEnumO(layout, op->type->idname, "direction");
04772                     uiPupMenuEnd(C, pup);
04773                     return OPERATOR_CANCELLED;
04774                 }
04775             }
04776         }
04777     }
04778 
04779     return toggle_cyclic_exec(C, op);
04780 }
04781 
04782 void CURVE_OT_cyclic_toggle(wmOperatorType *ot)
04783 {
04784     static EnumPropertyItem direction_items[]= {
04785         {0, "CYCLIC_U", 0, "Cyclic U", ""},
04786         {1, "CYCLIC_V", 0, "Cyclic V", ""},
04787         {0, NULL, 0, NULL, NULL}};
04788 
04789     /* identifiers */
04790     ot->name= "Toggle Cyclic";
04791     ot->description = "Make active spline closed/opened loop";
04792     ot->idname= "CURVE_OT_cyclic_toggle";
04793     
04794     /* api callbacks */
04795     ot->exec= toggle_cyclic_exec;
04796     ot->invoke= toggle_cyclic_invoke;
04797     ot->poll= ED_operator_editsurfcurve;
04798 
04799     /* flags */
04800     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04801 
04802     /* properties */
04803     RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to make surface cyclic in");
04804 }
04805 
04806 /***************** select linked operator ******************/
04807 
04808 static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
04809 {
04810     Object *obedit= CTX_data_edit_object(C);
04811     Curve *cu= (Curve*)obedit->data;
04812     EditNurb *editnurb= cu->editnurb;
04813     ListBase *nurbs= &editnurb->nurbs;
04814     Nurb *nu;
04815     BezTriple *bezt;
04816     BPoint *bp;
04817     int a;
04818 
04819     for(nu= nurbs->first; nu; nu= nu->next) {
04820         if(nu->type == CU_BEZIER) {
04821             bezt= nu->bezt;
04822             a= nu->pntsu;
04823             while(a--) {
04824                 if( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) {
04825                     a= nu->pntsu;
04826                     bezt= nu->bezt;
04827                     while(a--) {
04828                         select_beztriple(bezt, SELECT, 1, VISIBLE);
04829                         bezt++;
04830                     }
04831                     break;
04832                 }
04833                 bezt++;
04834             }
04835         }
04836         else {
04837             bp= nu->bp;
04838             a= nu->pntsu*nu->pntsv;
04839             while(a--) {
04840                 if( bp->f1 & 1 ) {
04841                     a= nu->pntsu*nu->pntsv;
04842                     bp= nu->bp;
04843                     while(a--) {
04844                         select_bpoint(bp, SELECT, 1, VISIBLE);
04845                         bp++;
04846                     }
04847                     break;
04848                 }
04849                 bp++;
04850             }
04851         }
04852     }
04853 
04854     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
04855 
04856     return OPERATOR_FINISHED;
04857 }
04858 
04859 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
04860 {
04861     return select_linked_exec(C, op);
04862 }
04863 
04864 void CURVE_OT_select_linked(wmOperatorType *ot)
04865 {
04866     /* identifiers */
04867     ot->name= "Select Linked All";
04868     ot->idname= "CURVE_OT_select_linked";
04869 
04870     /* api callbacks */
04871     ot->exec= select_linked_exec;
04872     ot->invoke= select_linked_invoke;
04873     ot->poll= ED_operator_editsurfcurve;
04874 
04875     /* flags */
04876     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04877 
04878     /* properties */
04879 }
04880 
04881 
04882 /***************** select linked pick operator ******************/
04883 
04884 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
04885 {
04886     Object *obedit= CTX_data_edit_object(C);
04887     ViewContext vc;
04888     Nurb *nu;
04889     BezTriple *bezt;
04890     BPoint *bp;
04891     int a, deselect;
04892 
04893     deselect= RNA_boolean_get(op->ptr, "deselect");
04894 
04895     view3d_operator_needs_opengl(C);
04896     view3d_set_viewcontext(C, &vc);
04897 
04898     findnearestNurbvert(&vc, 1, event->mval, &nu, &bezt, &bp);
04899 
04900     if(bezt) {
04901         a= nu->pntsu;
04902         bezt= nu->bezt;
04903         while(a--) {
04904             if(deselect) select_beztriple(bezt, DESELECT, 1, VISIBLE);
04905             else select_beztriple(bezt, SELECT, 1, VISIBLE);
04906             bezt++;
04907         }
04908     }
04909     else if(bp) {
04910         a= nu->pntsu*nu->pntsv;
04911         bp= nu->bp;
04912         while(a--) {
04913             if(deselect) select_bpoint(bp, DESELECT, 1, VISIBLE);
04914             else select_bpoint(bp, SELECT, 1, VISIBLE);
04915             bp++;
04916         }
04917     }
04918 
04919     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
04920 
04921     return OPERATOR_FINISHED;
04922 }
04923 
04924 void CURVE_OT_select_linked_pick(wmOperatorType *ot)
04925 {
04926     /* identifiers */
04927     ot->name= "Select Linked";
04928     ot->idname= "CURVE_OT_select_linked_pick";
04929 
04930     /* api callbacks */
04931     ot->invoke= select_linked_pick_invoke;
04932     ot->poll= ED_operator_editsurfcurve_region_view3d;
04933 
04934     /* flags */
04935     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
04936 
04937     /* properties */
04938     RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked control points rather than selecting them");
04939 }
04940 
04941 /***************** select row operator **********************/
04942 
04943 static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
04944 {
04945     Object *obedit= CTX_data_edit_object(C);
04946     Curve *cu= obedit->data;
04947     ListBase *editnurb= object_editcurve_get(obedit);
04948     static BPoint *last= NULL;
04949     static int direction=0;
04950     Nurb *nu;
04951     BPoint *bp;
04952     int u = 0, v = 0, a, b, ok=0;
04953 
04954     if(editnurb->first == NULL)
04955         return OPERATOR_CANCELLED;
04956     if(cu->lastsel==NULL)
04957         return OPERATOR_CANCELLED;
04958 
04959     /* find the correct nurb and toggle with u of v */
04960     for(nu= editnurb->first; nu; nu= nu->next) {
04961         bp= nu->bp;
04962         for(v=0; v<nu->pntsv; v++) {
04963             for(u=0; u<nu->pntsu; u++, bp++) {
04964                 if(bp==cu->lastsel) {
04965                     if(bp->f1 & SELECT) {
04966                         ok= 1;
04967                         break;
04968                     }
04969                 }
04970             }
04971             if(ok) break;
04972         }
04973 
04974         if(ok) {
04975             if(last==cu->lastsel) {
04976                 direction= 1-direction;
04977                 setflagsNurb(editnurb, 0);
04978             }
04979             last= cu->lastsel;
04980 
04981             bp= nu->bp;
04982             for(a=0; a<nu->pntsv; a++) {
04983                 for(b=0; b<nu->pntsu; b++, bp++) {
04984                     if(direction) {
04985                         if(a==v) select_bpoint(bp, SELECT, 1, VISIBLE);
04986                     }
04987                     else {
04988                         if(b==u) select_bpoint(bp, SELECT, 1, VISIBLE);
04989                     }
04990                 }
04991             }
04992 
04993             break;
04994         }
04995     }
04996     
04997     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
04998 
04999     return OPERATOR_FINISHED;
05000 }
05001 
05002 void CURVE_OT_select_row(wmOperatorType *ot)
05003 {
05004     /* identifiers */
05005     ot->name= "Select Control Point Row";
05006     ot->idname= "CURVE_OT_select_row";
05007     
05008     /* api callbacks */
05009     ot->exec= select_row_exec;
05010     ot->poll= ED_operator_editsurf;
05011 
05012     /* flags */
05013     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05014 }
05015 
05016 /***************** select next operator **********************/
05017 
05018 static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
05019 {
05020     Object *obedit= CTX_data_edit_object(C);
05021     ListBase *editnurb= object_editcurve_get(obedit);
05022     
05023     select_adjacent_cp(editnurb, 1, 0, SELECT);
05024     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
05025 
05026     return OPERATOR_FINISHED;
05027 }
05028 
05029 void CURVE_OT_select_next(wmOperatorType *ot)
05030 {
05031     /* identifiers */
05032     ot->name= "Select Next";
05033     ot->idname= "CURVE_OT_select_next";
05034     
05035     /* api callbacks */
05036     ot->exec= select_next_exec;
05037     ot->poll= ED_operator_editcurve;
05038 
05039     /* flags */
05040     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05041 }
05042 
05043 /***************** select previous operator **********************/
05044 
05045 static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
05046 {
05047     Object *obedit= CTX_data_edit_object(C);
05048     ListBase *editnurb= object_editcurve_get(obedit);
05049     
05050     select_adjacent_cp(editnurb, -1, 0, SELECT);
05051     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
05052 
05053     return OPERATOR_FINISHED;
05054 }
05055 
05056 void CURVE_OT_select_previous(wmOperatorType *ot)
05057 {
05058     /* identifiers */
05059     ot->name= "Select Previous";
05060     ot->idname= "CURVE_OT_select_previous";
05061     
05062     /* api callbacks */
05063     ot->exec= select_previous_exec;
05064     ot->poll= ED_operator_editcurve;
05065 
05066     /* flags */
05067     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05068 }
05069 
05070 /***************** select more operator **********************/
05071 
05072 static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
05073 {
05074     Object *obedit= CTX_data_edit_object(C);
05075     ListBase *editnurb= object_editcurve_get(obedit);
05076     Nurb *nu;
05077     BPoint *bp, *tempbp;
05078     int a;
05079     short sel= 0;
05080     short *selbpoints;
05081     
05082     /* note that NURBS surface is a special case because we mimic */
05083     /* the behaviour of "select more" of mesh tools.          */
05084     /* The algorithm is designed to work in planar cases so it    */
05085     /* may not be optimal always (example: end of NURBS sphere)   */
05086     if(obedit->type==OB_SURF) {
05087         for(nu= editnurb->first; nu; nu= nu->next) {
05088             a= nu->pntsu*nu->pntsv;
05089             bp= nu->bp;
05090             selbpoints= MEM_callocN(sizeof(short)*a-nu->pntsu, "selectlist");
05091             while(a > 0) {
05092                 if((selbpoints[a]!=1) && (bp->hide==0) && (bp->f1 & SELECT)) {
05093                     /* upper control point */
05094                     if(a%nu->pntsu != 0) {
05095                         tempbp= bp-1;
05096                         if(!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, 1, VISIBLE); 
05097                     }
05098 
05099                     /* left control point. select only if it is not selected already */
05100                     if(a-nu->pntsu > 0) {
05101                         sel= 0;
05102                         tempbp= bp+nu->pntsu;
05103                         if(!(tempbp->f1 & SELECT)) sel= select_bpoint(tempbp, SELECT, 1, VISIBLE); 
05104                         /* make sure selected bpoint is discarded */
05105                         if(sel == 1) selbpoints[a-nu->pntsu]= 1;
05106                     }
05107                     
05108                     /* right control point */
05109                     if(a+nu->pntsu < nu->pntsu*nu->pntsv) {
05110                         tempbp= bp-nu->pntsu;
05111                         if(!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, 1, VISIBLE); 
05112                     }
05113                 
05114                     /* lower control point. skip next bp in case selection was made */
05115                     if(a%nu->pntsu != 1) {
05116                         sel= 0;
05117                         tempbp= bp+1;
05118                         if(!(tempbp->f1 & 1)) sel= select_bpoint(tempbp, SELECT, 1, VISIBLE); 
05119                         if(sel) {
05120                             bp++;   
05121                             a--;
05122                         }
05123                     }               
05124                 }
05125 
05126                 bp++;
05127                 a--;
05128             }
05129             
05130             MEM_freeN(selbpoints);
05131         }
05132     }
05133     else {
05134         select_adjacent_cp(editnurb, 1, 0, SELECT);
05135         select_adjacent_cp(editnurb, -1, 0, SELECT);
05136     }
05137         
05138     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
05139 
05140     return OPERATOR_FINISHED;
05141 }
05142 
05143 void CURVE_OT_select_more(wmOperatorType *ot)
05144 {
05145     /* identifiers */
05146     ot->name= "Select More";
05147     ot->idname= "CURVE_OT_select_more";
05148     
05149     /* api callbacks */
05150     ot->exec= select_more_exec;
05151     ot->poll= ED_operator_editsurfcurve;
05152 
05153     /* flags */
05154     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05155 }
05156 
05157 /******************** select less operator *****************/
05158 
05159 /* basic method: deselect if control point doesn't have all neighbours selected */
05160 static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
05161 {
05162     Object *obedit= CTX_data_edit_object(C);
05163     ListBase *editnurb= object_editcurve_get(obedit);
05164     Nurb *nu;
05165     BPoint *bp;
05166     BezTriple *bezt;
05167     int a;
05168     short sel= 0, lastsel= 0;
05169     short *selbpoints;
05170     
05171     if(obedit->type==OB_SURF) {     
05172         for(nu= editnurb->first; nu; nu= nu->next) {
05173             a= nu->pntsu*nu->pntsv;
05174             bp= nu->bp;
05175             selbpoints= MEM_callocN(sizeof(short)*a, "selectlist");
05176             while(a--) {
05177                 if((bp->hide==0) && (bp->f1 & SELECT)) {
05178                     sel= 0;
05179                                     
05180                     /* check if neighbours have been selected */    
05181                     /* edges of surface are an exception */ 
05182                     if((a+1)%nu->pntsu==0) sel++;   
05183                     else {
05184                         bp--;
05185                         if((selbpoints[a+1]==1) || ((bp->hide==0) && (bp->f1 & SELECT))) sel++;
05186                         bp++;
05187                     }
05188                     
05189                     if((a+1)%nu->pntsu==1) sel++;
05190                     else {
05191                         bp++;
05192                         if((bp->hide==0) && (bp->f1 & SELECT)) sel++;
05193                         bp--;
05194                     }
05195                     
05196                     if(a+1 > nu->pntsu*nu->pntsv-nu->pntsu) sel++;
05197                     else {
05198                         bp-=nu->pntsu;
05199                         if((selbpoints[a+nu->pntsu]==1) || ((bp->hide==0) && (bp->f1 & SELECT))) sel++;
05200                         bp+=nu->pntsu;
05201                     }
05202                                     
05203                     if(a < nu->pntsu) sel++;
05204                     else {
05205                         bp+=nu->pntsu;
05206                         if((bp->hide==0) && (bp->f1 & SELECT)) sel++;
05207                         bp-=nu->pntsu;
05208                     }
05209                                                     
05210                     if(sel!=4) {
05211                         select_bpoint(bp, DESELECT, 1, VISIBLE); 
05212                         selbpoints[a]= 1;                                               
05213                     }                                   
05214                 }
05215                 else lastsel= 0;
05216                     
05217                 bp++;
05218             }
05219             
05220             MEM_freeN(selbpoints);
05221         }
05222     }
05223     else {
05224         for(nu= editnurb->first; nu; nu= nu->next) {
05225             lastsel=0;
05226             /* check what type of curve/nurb it is */
05227             if(nu->type == CU_BEZIER) {         
05228                 a= nu->pntsu;
05229                 bezt= nu->bezt;
05230                 while(a--) {
05231                     if((bezt->hide==0) && (bezt->f2 & SELECT)) {
05232                         if(lastsel==1) sel= 1;
05233                         else sel= 0;
05234                                                 
05235                         /* check if neighbours have been selected */                        
05236                         /* first and last are exceptions */                 
05237                         if(a==nu->pntsu-1) sel++; 
05238                         else { 
05239                             bezt--;
05240                             if((bezt->hide==0) && (bezt->f2 & SELECT)) sel++;
05241                             bezt++;
05242                         }
05243                         
05244                         if(a==0) sel++;
05245                         else {
05246                             bezt++;
05247                             if((bezt->hide==0) && (bezt->f2 & SELECT)) sel++;
05248                             bezt--;
05249                         }
05250 
05251                         if(sel!=2) {
05252                             select_beztriple(bezt, DESELECT, 1, VISIBLE);   
05253                             lastsel= 1;
05254                         }
05255                         else lastsel= 0;
05256                     }
05257                     else lastsel= 0;
05258                         
05259                     bezt++; 
05260                 }
05261             }
05262             else {
05263                 a= nu->pntsu*nu->pntsv;
05264                 bp= nu->bp;
05265                 while(a--) {
05266                     if((lastsel==0) && (bp->hide==0) && (bp->f1 & SELECT)) {
05267                         if(lastsel!=0) sel= 1;
05268                         else sel= 0;
05269                         
05270                         /* first and last are exceptions */                 
05271                         if(a==nu->pntsu*nu->pntsv-1) sel++; 
05272                         else { 
05273                             bp--;
05274                             if((bp->hide==0) && (bp->f1 & SELECT)) sel++;
05275                             bp++;
05276                         }
05277                         
05278                         if(a==0) sel++;
05279                         else {
05280                             bp++;
05281                             if((bp->hide==0) && (bp->f1 & SELECT)) sel++;
05282                             bp--;
05283                         }
05284                                             
05285                         if(sel!=2) {
05286                             select_bpoint(bp, DESELECT, 1, VISIBLE);    
05287                             lastsel= 1;                     
05288                         }               
05289                         else lastsel= 0;                    
05290                     }
05291                     else lastsel= 0;
05292                         
05293                     bp++;
05294                 }
05295             }
05296         }
05297     }
05298     
05299     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
05300 
05301     return OPERATOR_FINISHED;
05302 }
05303 
05304 void CURVE_OT_select_less(wmOperatorType *ot)
05305 {
05306     /* identifiers */
05307     ot->name= "Select Less";
05308     ot->idname= "CURVE_OT_select_less";
05309     
05310     /* api callbacks */
05311     ot->exec= select_less_exec;
05312     ot->poll= ED_operator_editsurfcurve;
05313 
05314     /* flags */
05315     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05316 }
05317 
05318 /********************** select random *********************/
05319 
05320 static void selectrandom_curve(ListBase *editnurb, float randfac)
05321 {
05322     Nurb *nu;
05323     BezTriple *bezt;
05324     BPoint *bp;
05325     int a;
05326     
05327     BLI_srand( BLI_rand() ); /* random seed */
05328     
05329     for(nu= editnurb->first; nu; nu= nu->next) {    
05330         if(nu->type == CU_BEZIER) {
05331             bezt= nu->bezt;
05332             a= nu->pntsu;
05333             while(a--) {
05334                 if (BLI_frand() < randfac)
05335                     select_beztriple(bezt, SELECT, 1, VISIBLE);
05336                 bezt++;
05337             }
05338         }
05339         else {
05340             bp= nu->bp;
05341             a= nu->pntsu*nu->pntsv;
05342             
05343             while(a--) {
05344                 if (BLI_frand() < randfac)
05345                     select_bpoint(bp, SELECT, 1, VISIBLE); 
05346                 bp++;
05347             }
05348         }       
05349     }
05350 }
05351 
05352 static int select_random_exec(bContext *C, wmOperator *op)
05353 {
05354     Object *obedit= CTX_data_edit_object(C);
05355     ListBase *editnurb= object_editcurve_get(obedit);
05356 
05357     if(!RNA_boolean_get(op->ptr, "extend"))
05358         CU_deselect_all(obedit);
05359     
05360     selectrandom_curve(editnurb, RNA_float_get(op->ptr, "percent")/100.0f);
05361     
05362     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
05363     
05364     return OPERATOR_FINISHED;
05365 }
05366 
05367 void CURVE_OT_select_random(wmOperatorType *ot)
05368 {
05369     /* identifiers */
05370     ot->name= "Select Random";
05371     ot->idname= "CURVE_OT_select_random";
05372     
05373     /* api callbacks */
05374     ot->exec= select_random_exec;
05375     ot->poll= ED_operator_editsurfcurve;
05376 
05377     /* flags */
05378     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05379 
05380     /* properties */
05381     RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
05382     RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first");
05383 }
05384 
05385 /********************* every nth number of point *******************/
05386 
05387 static int point_on_nurb(Nurb *nu, void *point)
05388 {
05389     if (nu->bezt) {
05390         BezTriple *bezt= (BezTriple*)point;
05391         return bezt >= nu->bezt && bezt < nu->bezt + nu->pntsu;
05392     } else {
05393         BPoint *bp= (BPoint*)point;
05394         return bp >= nu->bp && bp < nu->bp + nu->pntsu * nu->pntsv;
05395     }
05396 }
05397 
05398 static Nurb *get_lastsel_nurb(Curve *cu)
05399 {
05400     ListBase *nubase= curve_editnurbs(cu);
05401     Nurb *nu= nubase->first;
05402 
05403     if(!cu->lastsel)
05404         return NULL;
05405 
05406     while (nu) {
05407         if (point_on_nurb(nu, cu->lastsel))
05408             return nu;
05409 
05410         nu= nu->next;
05411     }
05412 
05413     return NULL;
05414 }
05415 
05416 static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth)
05417 {
05418     int a, start;
05419 
05420     start= bezt - nu->bezt;
05421     a= nu->pntsu;
05422     bezt= nu->bezt + a - 1;
05423 
05424     while (a--) {
05425         if (abs(start - a) % nth) {
05426             select_beztriple(bezt, DESELECT, 1, HIDDEN);
05427         }
05428 
05429         bezt--;
05430     }
05431 }
05432 
05433 static void select_nth_bp(Nurb *nu, BPoint *bp, int nth)
05434 {
05435     int a, startrow, startpnt;
05436     int dist, row, pnt;
05437 
05438     startrow= (bp - nu->bp) / nu->pntsu;
05439     startpnt= (bp - nu->bp) % nu->pntsu;
05440 
05441     a= nu->pntsu * nu->pntsv;
05442     bp= nu->bp + a - 1;
05443     row = nu->pntsv - 1;
05444     pnt = nu->pntsu - 1;
05445 
05446     while (a--) {
05447         dist= abs(pnt - startpnt) + abs(row - startrow);
05448         if (dist % nth) {
05449             select_bpoint(bp, DESELECT, 1, HIDDEN);
05450         }
05451 
05452         pnt--;
05453         if (pnt < 0) {
05454             pnt= nu->pntsu - 1;
05455             row--;
05456         }
05457 
05458         bp--;
05459     }
05460 }
05461 
05462 int CU_select_nth(Object *obedit, int nth)
05463 {
05464     Curve *cu= (Curve*)obedit->data;
05465     Nurb *nu;
05466 
05467     nu= get_lastsel_nurb(cu);
05468     if (!nu)
05469         return 0;
05470 
05471     if (nu->bezt) {
05472         select_nth_bezt(nu, cu->lastsel, nth);
05473     } else {
05474         select_nth_bp(nu, cu->lastsel, nth);
05475     }
05476 
05477     return 1;
05478 }
05479 
05480 static int select_nth_exec(bContext *C, wmOperator *op)
05481 {
05482     Object *obedit= CTX_data_edit_object(C);
05483     int nth= RNA_int_get(op->ptr, "nth");
05484 
05485     if (!CU_select_nth(obedit, nth)) {
05486         if (obedit->type == OB_SURF) {
05487             BKE_report(op->reports, RPT_ERROR, "Surface hasn't got active point");
05488         } else {
05489             BKE_report(op->reports, RPT_ERROR, "Curve hasn't got active point");
05490         }
05491 
05492         return OPERATOR_CANCELLED;
05493     }
05494 
05495     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
05496 
05497     return OPERATOR_FINISHED;
05498 }
05499 
05500 void CURVE_OT_select_nth(wmOperatorType *ot)
05501 {
05502     /* identifiers */
05503     ot->name= "Select Nth";
05504     ot->description= "";
05505     ot->idname= "CURVE_OT_select_nth";
05506 
05507     /* api callbacks */
05508     ot->exec= select_nth_exec;
05509     ot->poll= ED_operator_editsurfcurve;
05510 
05511     /* flags */
05512     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05513 
05514     RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX);
05515 }
05516 
05517 /********************** add duplicate operator *********************/
05518 
05519 static int duplicate_exec(bContext *C, wmOperator *UNUSED(op))
05520 {
05521     Object *obedit= CTX_data_edit_object(C);
05522 
05523     adduplicateflagNurb(obedit, 1);
05524     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
05525 
05526     return OPERATOR_FINISHED;
05527 }
05528 
05529 void CURVE_OT_duplicate(wmOperatorType *ot)
05530 {
05531     /* identifiers */
05532     ot->name= "Duplicate Curve";
05533     ot->description = "Duplicate selected control points and segments between them";
05534     ot->idname= "CURVE_OT_duplicate";
05535     
05536     /* api callbacks */
05537     ot->exec= duplicate_exec;
05538     ot->poll= ED_operator_editsurfcurve;
05539     
05540     /* flags */
05541     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05542 }
05543 
05544 /********************** delete operator *********************/
05545 
05546 static int delete_exec(bContext *C, wmOperator *op)
05547 {
05548     Object *obedit= CTX_data_edit_object(C);
05549     Curve *cu= obedit->data;
05550     EditNurb *editnurb= cu->editnurb;
05551     ListBase *nubase= &editnurb->nurbs;
05552     Nurb *nu, *nu1;
05553     BezTriple *bezt, *bezt1, *bezt2;
05554     BPoint *bp, *bp1, *bp2;
05555     int a, cut= 0, type= RNA_enum_get(op->ptr, "type");
05556     int nuindex= 0;
05557 
05558     if(obedit->type==OB_SURF) {
05559         if(type==0) {
05560             deleteflagNurb(C, op, 1);
05561         } else {
05562             keyIndex_delNurbList(editnurb, nubase);
05563             freeNurblist(nubase);
05564 
05565             if(ED_curve_updateAnimPaths(obedit))
05566                 WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
05567         }
05568 
05569         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
05570         DAG_id_tag_update(obedit->data, 0);
05571     
05572         return OPERATOR_FINISHED;
05573     }
05574 
05575     if(type==0) {
05576         /* first loop, can we remove entire pieces? */
05577         Nurb *next;
05578         nu= nubase->first;
05579         while(nu) {
05580             next= nu->next;
05581             if(nu->type == CU_BEZIER) {
05582                 bezt= nu->bezt;
05583                 a= nu->pntsu;
05584                 if(a) {
05585                     while(a) {
05586                         if( BEZSELECTED_HIDDENHANDLES(cu, bezt) );
05587                         else break;
05588                         a--;
05589                         bezt++;
05590                     }
05591                     if(a==0) {
05592                         if(cu->actnu == nuindex)
05593                             cu->actnu= -1;
05594 
05595                         BLI_remlink(nubase, nu);
05596                         keyIndex_delNurb(editnurb, nu);
05597                         freeNurb(nu); nu= NULL;
05598                     }
05599                 }
05600             }
05601             else {
05602                 bp= nu->bp;
05603                 a= nu->pntsu*nu->pntsv;
05604                 if(a) {
05605                     while(a) {
05606                         if(bp->f1 & SELECT);
05607                         else break;
05608                         a--;
05609                         bp++;
05610                     }
05611                     if(a==0) {
05612                         if(cu->actnu == nuindex)
05613                             cu->actnu= -1;
05614 
05615                         BLI_remlink(nubase, nu);
05616                         keyIndex_delNurb(editnurb, nu);
05617                         freeNurb(nu); nu= NULL;
05618                     }
05619                 }
05620             }
05621             
05622             /* Never allow the order to exceed the number of points
05623             - note, this is ok but changes unselected nurbs, disable for now */
05624             /*
05625             if ((nu!= NULL) && (nu->type == CU_NURBS)) {
05626                 clamp_nurb_order_u(nu);
05627             }
05628             */
05629             nu= next;
05630             nuindex++;
05631         }
05632         /* 2nd loop, delete small pieces: just for curves */
05633         nu= nubase->first;
05634         while(nu) {
05635             next= nu->next;
05636             type= 0;
05637             if(nu->type == CU_BEZIER) {
05638                 int delta= 0;
05639                 bezt= nu->bezt;
05640                 for(a=0;a<nu->pntsu;a++) {
05641                     if( BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
05642                         memmove(bezt, bezt+1, (nu->pntsu-a-1)*sizeof(BezTriple));
05643                         keyIndex_delBezt(editnurb, bezt + delta);
05644                         keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu-a-1);
05645                         nu->pntsu--;
05646                         a--;
05647                         type= 1;
05648                         delta++;
05649                     }
05650                     else bezt++;
05651                 }
05652                 if(type) {
05653                     bezt1 =
05654                         (BezTriple*)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "delNurb");
05655                     memcpy(bezt1, nu->bezt, (nu->pntsu)*sizeof(BezTriple) );
05656                     keyIndex_updateBezt(editnurb, nu->bezt, bezt1, nu->pntsu);
05657                     MEM_freeN(nu->bezt);
05658                     nu->bezt= bezt1;
05659                     calchandlesNurb(nu);
05660                 }
05661             }
05662             else if(nu->pntsv==1) {
05663                 int delta= 0;
05664                 bp= nu->bp;
05665                 
05666                 for(a=0;a<nu->pntsu;a++) {
05667                     if( bp->f1 & SELECT ) {
05668                         memmove(bp, bp+1, (nu->pntsu-a-1)*sizeof(BPoint));
05669                         keyIndex_delBP(editnurb, bp + delta);
05670                         keyIndex_updateBP(editnurb, bp+1, bp, nu->pntsu-a-1);
05671                         nu->pntsu--;
05672                         a--;
05673                         type= 1;
05674                         delta++;
05675                     }
05676                     else {
05677                         bp++;
05678                     }
05679                 }
05680                 if(type) {
05681                     bp1 = (BPoint*)MEM_mallocN(nu->pntsu * sizeof(BPoint), "delNurb2");
05682                     memcpy(bp1, nu->bp, (nu->pntsu)*sizeof(BPoint) );
05683                     keyIndex_updateBP(editnurb, nu->bp, bp1, nu->pntsu);
05684                     MEM_freeN(nu->bp);
05685                     nu->bp= bp1;
05686                     
05687                     /* Never allow the order to exceed the number of points\
05688                     - note, this is ok but changes unselected nurbs, disable for now */
05689                     /*
05690                     if (nu->type == CU_NURBS) {
05691                         clamp_nurb_order_u(nu);
05692                     }*/
05693                 }
05694                 clamp_nurb_order_u(nu);
05695                 nurbs_knot_calc_u(nu);
05696             }
05697             nu= next;
05698         }
05699     }
05700     else if(type==1) {  /* erase segment */
05701         /* find the 2 selected points */
05702         bezt1= bezt2= NULL;
05703         bp1= bp2= NULL;
05704         nu1= NULL;
05705         nuindex= 0;
05706         for(nu= nubase->first; nu; nu= nu->next) {
05707             if(nu->type == CU_BEZIER) {
05708                 bezt= nu->bezt;
05709                 for(a=0; a<nu->pntsu-1; a++) {
05710                     if( BEZSELECTED_HIDDENHANDLES(cu, bezt) ) {
05711                         bezt1= bezt;
05712                         bezt2= bezt+1;
05713                         if( (bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT) ) ;
05714                         else {  /* maybe do not make cyclic */
05715                             if(a==0 && (nu->flagu & CU_NURB_CYCLIC) ) {
05716                                 bezt2= bezt+(nu->pntsu-1);
05717                                 if( (bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT) ) {
05718                                     nu->flagu &= ~CU_NURB_CYCLIC;
05719                                     calchandlesNurb(nu);
05720                                     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
05721                                     DAG_id_tag_update(obedit->data, 0);
05722                                 }
05723                             }
05724 
05725                             return OPERATOR_FINISHED;
05726                         }
05727                         cut= a;
05728                         nu1= nu;
05729                         break;
05730                     }
05731                     bezt++;
05732                 }
05733             }
05734             else if(nu->pntsv==1) {
05735                 bp= nu->bp;
05736                 for(a=0; a<nu->pntsu-1; a++) {
05737                     if( bp->f1 & SELECT ) {
05738                         bp1= bp;
05739                         bp2= bp+1;
05740                         if( bp2->f1 & 1 ) ;
05741                         else {  /* maybe do not make cyclic */
05742                             if(a==0 && (nu->flagu & CU_NURB_CYCLIC) ) {
05743                                 bp2= bp+(nu->pntsu-1);
05744                                 if( bp2->f1 & SELECT ) {
05745                                     nu->flagu &= ~CU_NURB_CYCLIC;
05746                                     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
05747                                     DAG_id_tag_update(obedit->data, 0);
05748                                 }
05749                             }
05750 
05751                             return OPERATOR_FINISHED;
05752                         }
05753                         cut= a;
05754                         nu1= nu;
05755                         break;
05756                     }
05757                     bp++;
05758                 }
05759             }
05760             if(nu1) break;
05761             nuindex++;
05762         }
05763         if(nu1) {
05764             if(bezt1) {
05765                 if(nu1->pntsu==2) { /* remove completely */
05766                     if(cu->actnu == nuindex)
05767                         cu->actnu= -1;
05768 
05769                     BLI_remlink(nubase, nu);
05770                     freeNurb(nu); nu = NULL;
05771                 }
05772                 else if(nu1->flagu & CU_NURB_CYCLIC) {  /* cyclic */
05773                     bezt =
05774                         (BezTriple*)MEM_mallocN((cut+1) * sizeof(BezTriple), "delNurb1");
05775                     ED_curve_beztcpy(editnurb, bezt, nu1->bezt, cut+1);
05776                     a= nu1->pntsu-cut-1;
05777                     ED_curve_beztcpy(editnurb, nu1->bezt, bezt2, a);
05778                     ED_curve_beztcpy(editnurb, nu1->bezt+a, bezt, cut+1);
05779 
05780                     nu1->flagu &= ~CU_NURB_CYCLIC;
05781                     MEM_freeN(bezt);
05782                     calchandlesNurb(nu);
05783                 }
05784                 else {          /* add new curve */
05785 
05786 /* seems to be an error here... but where? (a can become zero) */
05787 
05788                     nu =
05789                         (Nurb*)MEM_mallocN(sizeof(Nurb), "delNurb2");
05790                     memcpy(nu, nu1, sizeof(Nurb));
05791                     BLI_addtail(nubase, nu);
05792                     nu->bezt =
05793                         (BezTriple*)MEM_mallocN((cut+1) * sizeof(BezTriple), "delNurb3");
05794                     ED_curve_beztcpy(editnurb, nu->bezt, nu1->bezt, cut+1);
05795                     a= nu1->pntsu-cut-1;
05796                     
05797                     bezt =
05798                         (BezTriple*)MEM_mallocN(a * sizeof(BezTriple), "delNurb4");
05799                     ED_curve_beztcpy(editnurb, bezt, nu1->bezt+cut+1, a);
05800                     MEM_freeN(nu1->bezt);
05801                     nu1->bezt= bezt;
05802                     nu1->pntsu= a;
05803                     nu->pntsu= cut+1;
05804                     
05805                     
05806                     calchandlesNurb(nu);
05807                     calchandlesNurb(nu1);
05808                 }
05809             }
05810             else if(bp1) {
05811                 if(nu1->pntsu==2) { /* remove completely */
05812                     if(cu->actnu == nuindex)
05813                         cu->actnu= -1;
05814 
05815                     BLI_remlink(nubase, nu);
05816                     freeNurb(nu); nu= NULL;
05817                 }
05818                 else if(nu1->flagu & CU_NURB_CYCLIC) {  /* cyclic */
05819                     bp =
05820                         (BPoint*)MEM_mallocN((cut+1) * sizeof(BPoint), "delNurb5");
05821                     ED_curve_bpcpy(editnurb, bp, nu1->bp, cut+1);
05822                     a= nu1->pntsu-cut-1;
05823                     ED_curve_bpcpy(editnurb, nu1->bp, bp2, a);
05824                     ED_curve_bpcpy(editnurb, nu1->bp+a, bp, cut+1);
05825 
05826                     nu1->flagu &= ~CU_NURB_CYCLIC;
05827                     MEM_freeN(bp);
05828                 }
05829                 else {          /* add new curve */
05830                     nu = (Nurb*)MEM_mallocN(sizeof(Nurb), "delNurb6");
05831                     memcpy(nu, nu1, sizeof(Nurb));
05832                     BLI_addtail(nubase, nu);
05833                     nu->bp =
05834                         (BPoint*)MEM_mallocN((cut+1) * sizeof(BPoint), "delNurb7");
05835                     ED_curve_bpcpy(editnurb, nu->bp, nu1->bp, cut+1);
05836                     a= nu1->pntsu-cut-1;
05837                     bp =
05838                         (BPoint*)MEM_mallocN(a * sizeof(BPoint), "delNurb8");
05839                     ED_curve_bpcpy(editnurb, bp, nu1->bp+cut+1, a);
05840                     MEM_freeN(nu1->bp);
05841                     nu1->bp= bp;
05842                     nu1->pntsu= a;
05843                     nu1->knotsu= NULL;
05844                     nu->pntsu= cut+1;
05845 
05846                     clamp_nurb_order_u(nu);
05847                     nurbs_knot_calc_u(nu);
05848 
05849                     clamp_nurb_order_u(nu1);
05850                     nurbs_knot_calc_u(nu1);
05851                 }
05852             }
05853         }
05854     }
05855     else if(type==2) {
05856         cu->actnu= -1;
05857         keyIndex_delNurbList(editnurb, nubase);
05858         freeNurblist(nubase);
05859     }
05860 
05861     if(ED_curve_updateAnimPaths(obedit))
05862         WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obedit);
05863 
05864     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
05865     DAG_id_tag_update(obedit->data, 0);
05866     
05867     return OPERATOR_FINISHED;
05868 }
05869 
05870 static int delete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
05871 {
05872     Object *obedit= CTX_data_edit_object(C);
05873     uiPopupMenu *pup;
05874     uiLayout *layout;
05875 
05876     if(obedit->type==OB_SURF) {
05877         pup= uiPupMenuBegin(C, "Delete", ICON_NONE);
05878         layout= uiPupMenuLayout(pup);
05879         uiItemEnumO(layout, op->type->idname, NULL, 0, "type", 0);
05880         uiItemEnumO(layout, op->type->idname, NULL, 0, "type", 2);
05881         uiPupMenuEnd(C, pup);
05882     }
05883     else {
05884         pup= uiPupMenuBegin(C, "Delete", ICON_NONE);
05885         layout= uiPupMenuLayout(pup);
05886         uiItemsEnumO(layout, op->type->idname, "type");
05887         uiPupMenuEnd(C, pup);
05888     }
05889 
05890     return OPERATOR_CANCELLED;
05891 }
05892 
05893 void CURVE_OT_delete(wmOperatorType *ot)
05894 {
05895     static EnumPropertyItem type_items[] = {
05896         {0, "SELECTED", 0, "Select", ""},
05897         {1, "SEGMENT", 0, "Segment", ""},
05898         {2, "ALL", 0, "All", ""},
05899         {0, NULL, 0, NULL, NULL}};
05900 
05901     /* identifiers */
05902     ot->name= "Delete";
05903     ot->description = "Delete selected control points or segments";
05904     ot->idname= "CURVE_OT_delete";
05905     
05906     /* api callbacks */
05907     ot->exec= delete_exec;
05908     ot->invoke= delete_invoke;
05909     ot->poll= ED_operator_editsurfcurve;
05910     
05911     /* flags */
05912     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05913 
05914     /* properties */
05915     RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Which elements to delete");
05916 }
05917 
05918 /********************** shade smooth/flat operator *********************/
05919 
05920 static int shade_smooth_exec(bContext *C, wmOperator *op)
05921 {
05922     Object *obedit= CTX_data_edit_object(C);
05923     ListBase *editnurb= object_editcurve_get(obedit);
05924     Nurb *nu;
05925     int clear= (strcmp(op->idname, "CURVE_OT_shade_flat") == 0);
05926     
05927     if(obedit->type != OB_CURVE)
05928         return OPERATOR_CANCELLED;
05929     
05930     for(nu= editnurb->first; nu; nu= nu->next) {
05931         if(isNurbsel(nu)) {
05932             if(!clear) nu->flag |= CU_SMOOTH;
05933             else nu->flag &= ~CU_SMOOTH;
05934         }
05935     }
05936     
05937     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
05938     DAG_id_tag_update(obedit->data, 0);
05939 
05940     return OPERATOR_FINISHED;
05941 }
05942 
05943 void CURVE_OT_shade_smooth(wmOperatorType *ot)
05944 {
05945     /* identifiers */
05946     ot->name= "Shade Smooth";
05947     ot->idname= "CURVE_OT_shade_smooth";
05948     
05949     /* api callbacks */
05950     ot->exec= shade_smooth_exec;
05951     ot->poll= ED_operator_editsurfcurve;
05952     
05953     /* flags */
05954     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05955 }
05956 
05957 void CURVE_OT_shade_flat(wmOperatorType *ot)
05958 {
05959     /* identifiers */
05960     ot->name= "Shade Flat";
05961     ot->idname= "CURVE_OT_shade_flat";
05962     
05963     /* api callbacks */
05964     ot->exec= shade_smooth_exec;
05965     ot->poll= ED_operator_editsurfcurve;
05966     
05967     /* flags */
05968     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
05969 }
05970 
05971 /************** join operator, to be used externally? ****************/
05972 
05973 int join_curve_exec(bContext *C, wmOperator *UNUSED(op))
05974 {
05975     Main *bmain= CTX_data_main(C);
05976     Scene *scene= CTX_data_scene(C);
05977     Object *ob= CTX_data_active_object(C);
05978     Curve *cu;
05979     Nurb *nu, *newnu;
05980     BezTriple *bezt;
05981     BPoint *bp;
05982     ListBase tempbase;
05983     float imat[4][4], cmat[4][4];
05984     int a;
05985 
05986     tempbase.first= tempbase.last= NULL;
05987     
05988     /* trasnform all selected curves inverse in obact */
05989     invert_m4_m4(imat, ob->obmat);
05990     
05991     CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
05992         if(base->object->type==ob->type) {
05993             if(base->object != ob) {
05994             
05995                 cu= base->object->data;
05996             
05997                 if(cu->nurb.first) {
05998                     /* watch it: switch order here really goes wrong */
05999                     mult_m4_m4m4(cmat, imat, base->object->obmat);
06000                     
06001                     nu= cu->nurb.first;
06002                     while(nu) {
06003                         newnu= duplicateNurb(nu);
06004                         if(ob->totcol) { /* TODO, merge material lists */
06005                             CLAMP(newnu->mat_nr, 0, ob->totcol-1);
06006                         } else newnu->mat_nr= 0;
06007                         BLI_addtail(&tempbase, newnu);
06008                         
06009                         if( (bezt= newnu->bezt) ) {
06010                             a= newnu->pntsu;
06011                             while(a--) {
06012                                 mul_m4_v3(cmat, bezt->vec[0]);
06013                                 mul_m4_v3(cmat, bezt->vec[1]);
06014                                 mul_m4_v3(cmat, bezt->vec[2]);
06015                                 bezt++;
06016                             }
06017                             calchandlesNurb(newnu);
06018                         }
06019                         if( (bp= newnu->bp) ) {
06020                             a= newnu->pntsu*nu->pntsv;
06021                             while(a--) {
06022                                 mul_m4_v3(cmat, bp->vec);
06023                                 bp++;
06024                             }
06025                         }
06026                         nu= nu->next;
06027                     }
06028                 }
06029             
06030                 ED_base_object_free_and_unlink(bmain, scene, base);
06031             }
06032         }
06033     }
06034     CTX_DATA_END;
06035     
06036     cu= ob->data;
06037     BLI_movelisttolist(&cu->nurb, &tempbase);
06038     
06039     DAG_scene_sort(bmain, scene);   // because we removed object(s), call before editmode!
06040     
06041     ED_object_enter_editmode(C, EM_WAITCURSOR);
06042     ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO);
06043 
06044     WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
06045 
06046     return OPERATOR_FINISHED;
06047 }
06048 
06049 /************ add primitive, used by object/ module ****************/
06050 
06051 static const char *get_curve_defname(int type)
06052 {
06053     int stype= type & CU_PRIMITIVE;
06054 
06055     if((type & CU_TYPE)==CU_BEZIER) {
06056         switch (stype) {
06057             case CU_PRIM_CURVE: return "BezierCurve";
06058             case CU_PRIM_CIRCLE: return "BezierCircle";
06059             case CU_PRIM_PATH: return "CurvePath";
06060             default:
06061                 return "Curve";
06062         }
06063     }
06064     else {
06065         switch (stype) {
06066             case CU_PRIM_CURVE: return "NurbsCurve";
06067             case CU_PRIM_CIRCLE: return "NurbsCircle";
06068             case CU_PRIM_PATH: return "NurbsPath";
06069             default:
06070                 return "Curve";
06071         }
06072     }
06073 }
06074 
06075 static const char *get_surf_defname(int type)
06076 {
06077     int stype= type & CU_PRIMITIVE;
06078 
06079     switch (stype) {
06080         case CU_PRIM_CURVE: return "SurfCurve";
06081         case CU_PRIM_CIRCLE: return "SurfCircle";
06082         case CU_PRIM_PATCH: return "SurfPatch";
06083         case CU_PRIM_SPHERE: return "SurfSphere";
06084         case CU_PRIM_DONUT: return "SurfTorus";
06085         default:
06086             return "Surface";
06087     }
06088 }
06089 
06090 
06091 Nurb *add_nurbs_primitive(bContext *C, float mat[4][4], int type, int newob)
06092 {
06093     static int xzproj= 0;   /* this function calls itself... */
06094     Object *obedit= CTX_data_edit_object(C);
06095     ListBase *editnurb= object_editcurve_get(obedit);
06096     View3D *v3d= CTX_wm_view3d(C);
06097     RegionView3D *rv3d= ED_view3d_context_rv3d(C);
06098     Nurb *nu = NULL;
06099     BezTriple *bezt;
06100     BPoint *bp;
06101     Curve *cu= (Curve*)obedit->data;
06102     float vec[3], zvec[3]= {0.0f, 0.0f, 1.0f};
06103     float umat[4][4]= MAT4_UNITY, viewmat[4][4]= MAT4_UNITY;
06104     float fac;
06105     int a, b;
06106     const float grid= v3d ? v3d->grid : 1.0f;
06107     const int cutype= (type & CU_TYPE); // poly, bezier, nurbs, etc
06108     const int stype= (type & CU_PRIMITIVE);
06109     const int force_3d = ((Curve *)obedit->data)->flag & CU_3D; /* could be adding to an existing 3D curve */
06110 
06111     if(rv3d) {
06112         copy_m4_m4(viewmat, rv3d->viewmat);
06113         copy_v3_v3(zvec, rv3d->viewinv[2]);
06114     }
06115 
06116     setflagsNurb(editnurb, 0);
06117     
06118     /* these types call this function to return a Nurb */
06119     if (stype!=CU_PRIM_TUBE && stype!=CU_PRIM_DONUT) {
06120         nu = (Nurb*)MEM_callocN(sizeof(Nurb), "addNurbprim");
06121         nu->type= cutype;
06122         nu->resolu= cu->resolu;
06123         nu->resolv= cu->resolv;
06124     }
06125 
06126     switch(stype) {
06127     case CU_PRIM_CURVE: /* curve */
06128         nu->resolu= cu->resolu;
06129         if(cutype==CU_BEZIER) {
06130             if (!force_3d) nu->flag |= CU_2D;
06131             nu->pntsu= 2;
06132             nu->bezt =
06133                 (BezTriple*)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1");
06134             bezt= nu->bezt;
06135             bezt->h1= bezt->h2= HD_ALIGN;
06136             bezt->f1= bezt->f2= bezt->f3= SELECT;
06137             bezt->radius = 1.0;
06138 
06139             bezt->vec[1][0]+= -grid;
06140             bezt->vec[0][0]+= -1.5f*grid;
06141             bezt->vec[0][1]+= -0.5f*grid;
06142             bezt->vec[2][0]+= -0.5f*grid;
06143             bezt->vec[2][1]+=  0.5f*grid;
06144             for(a=0;a<3;a++) mul_m4_v3(mat, bezt->vec[a]);
06145 
06146             bezt++;
06147             bezt->h1= bezt->h2= HD_ALIGN;
06148             bezt->f1= bezt->f2= bezt->f3= SELECT;
06149             bezt->radius = bezt->weight = 1.0;
06150 
06151             bezt->vec[0][0] = 0;
06152             bezt->vec[0][1] = 0;
06153             bezt->vec[1][0] = grid;
06154             bezt->vec[1][1] = 0;
06155             bezt->vec[2][0] = grid*2;
06156             bezt->vec[2][1] = 0;
06157             for(a=0;a<3;a++) mul_m4_v3(mat, bezt->vec[a]);
06158 
06159             calchandlesNurb(nu);
06160         }
06161         else {
06162             
06163             nu->pntsu= 4;
06164             nu->pntsv= 1;
06165             nu->orderu= 4;
06166             nu->bp= callocstructN(BPoint, 4, "addNurbprim3");
06167 
06168             bp= nu->bp;
06169             for(a=0;a<4;a++, bp++) {
06170                 bp->vec[3]= 1.0;
06171                 bp->f1= SELECT;
06172                 bp->radius = bp->weight = 1.0;
06173             }
06174 
06175             bp= nu->bp;
06176             bp->vec[0]+= -1.5f*grid;
06177             bp++;
06178             bp->vec[0]+= -grid;
06179             bp->vec[1]+=  grid; 
06180             bp++;
06181             bp->vec[0]+= grid;
06182             bp->vec[1]+= grid; 
06183             bp++;
06184             bp->vec[0]+= 1.5f*grid;
06185 
06186             bp= nu->bp;
06187             for(a=0;a<4;a++, bp++) mul_m4_v3(mat,bp->vec);
06188 
06189             if(cutype==CU_NURBS) {
06190                 nu->knotsu= NULL;   /* nurbs_knot_calc_u allocates */
06191                 nurbs_knot_calc_u(nu);
06192             }
06193 
06194         }
06195         break;
06196     case CU_PRIM_PATH:  /* 5 point path */
06197         nu->pntsu= 5;
06198         nu->pntsv= 1;
06199         nu->orderu= 5;
06200         nu->flagu= CU_NURB_ENDPOINT;    /* endpoint */
06201         nu->resolu= cu->resolu;
06202         nu->bp= callocstructN(BPoint, 5, "addNurbprim3");
06203 
06204         bp= nu->bp;
06205         for(a=0;a<5;a++, bp++) {
06206             bp->vec[3]= 1.0;
06207             bp->f1= SELECT;
06208             bp->radius = bp->weight = 1.0;
06209         }
06210 
06211         bp= nu->bp;
06212         bp->vec[0]+= -2.0f*grid;
06213         bp++;
06214         bp->vec[0]+= -grid;
06215         bp++; bp++;
06216         bp->vec[0]+= grid;
06217         bp++;
06218         bp->vec[0]+= 2.0f*grid;
06219 
06220         bp= nu->bp;
06221         for(a=0;a<5;a++, bp++) mul_m4_v3(mat,bp->vec);
06222 
06223         if(cutype==CU_NURBS) {
06224             nu->knotsu= NULL;   /* nurbs_knot_calc_u allocates */
06225             nurbs_knot_calc_u(nu);
06226         }
06227 
06228         break;
06229     case CU_PRIM_CIRCLE:    /* circle */
06230         nu->resolu= cu->resolu;
06231 
06232         if(cutype==CU_BEZIER) {
06233             if (!force_3d) nu->flag |= CU_2D;
06234             nu->pntsu= 4;
06235             nu->bezt= callocstructN(BezTriple, 4, "addNurbprim1");
06236             nu->flagu= CU_NURB_CYCLIC;
06237             bezt= nu->bezt;
06238 
06239             bezt->h1= bezt->h2= HD_AUTO;
06240             bezt->f1= bezt->f2= bezt->f3= SELECT;
06241             bezt->vec[1][0]+= -grid;
06242             for(a=0;a<3;a++) mul_m4_v3(mat,bezt->vec[a]);
06243             bezt->radius = bezt->weight = 1.0;
06244             
06245             bezt++;
06246             bezt->h1= bezt->h2= HD_AUTO;
06247             bezt->f1= bezt->f2= bezt->f3= SELECT;
06248             bezt->vec[1][1]+= grid;
06249             for(a=0;a<3;a++) mul_m4_v3(mat,bezt->vec[a]);
06250             bezt->radius = bezt->weight = 1.0;
06251 
06252             bezt++;
06253             bezt->h1= bezt->h2= HD_AUTO;
06254             bezt->f1= bezt->f2= bezt->f3= SELECT;
06255             bezt->vec[1][0]+= grid;
06256             for(a=0;a<3;a++) mul_m4_v3(mat,bezt->vec[a]);
06257             bezt->radius = bezt->weight = 1.0;
06258 
06259             bezt++;
06260             bezt->h1= bezt->h2= HD_AUTO;
06261             bezt->f1= bezt->f2= bezt->f3= SELECT;
06262             bezt->vec[1][1]+= -grid;
06263             for(a=0;a<3;a++) mul_m4_v3(mat,bezt->vec[a]);
06264             bezt->radius = bezt->weight = 1.0;
06265 
06266             calchandlesNurb(nu);
06267         }
06268         else if( cutype==CU_NURBS ) {  /* nurb */
06269             nu->pntsu= 8;
06270             nu->pntsv= 1;
06271             nu->orderu= 4;
06272             nu->bp= callocstructN(BPoint, 8, "addNurbprim6");
06273             nu->flagu= CU_NURB_CYCLIC;
06274             bp= nu->bp;
06275 
06276             for(a=0; a<8; a++) {
06277                 bp->f1= SELECT;
06278                 if(xzproj==0) {
06279                     bp->vec[0]+= nurbcircle[a][0]*grid;
06280                     bp->vec[1]+= nurbcircle[a][1]*grid;
06281                 }
06282                 else {
06283                     bp->vec[0]+= 0.25f*nurbcircle[a][0]*grid-0.75f*grid;
06284                     bp->vec[2]+= 0.25f*nurbcircle[a][1]*grid;
06285                 }
06286                 if(a & 1) bp->vec[3]= 0.25*M_SQRT2;
06287                 else bp->vec[3]= 1.0;
06288                 mul_m4_v3(mat,bp->vec);
06289                 bp->radius = bp->weight = 1.0;
06290                 
06291                 bp++;
06292             }
06293 
06294             nurbs_knot_calc_u(nu);
06295         }
06296         break;
06297     case CU_PRIM_PATCH: /* 4x4 patch */
06298         if( cutype==CU_NURBS ) {  /* nurb */
06299 
06300             nu->pntsu= 4;
06301             nu->pntsv= 4;
06302             nu->orderu= 4;
06303             nu->orderv= 4;
06304             nu->flag= CU_SMOOTH;
06305             nu->bp= callocstructN(BPoint, 4*4, "addNurbprim6");
06306             nu->flagu= 0;
06307             nu->flagv= 0;
06308             bp= nu->bp;
06309 
06310             for(a=0; a<4; a++) {
06311                 for(b=0; b<4; b++) {
06312                     bp->f1= SELECT;
06313                     fac= (float)a -1.5f;
06314                     bp->vec[0]+= fac*grid;
06315                     fac= (float)b -1.5f;
06316                     bp->vec[1]+= fac*grid;
06317                     if(a==1 || a==2) if(b==1 || b==2) {
06318                         bp->vec[2]+= grid;
06319                     }
06320                     mul_m4_v3(mat,bp->vec);
06321                     bp->vec[3]= 1.0;
06322                     bp++;
06323                 }
06324             }
06325 
06326             nurbs_knot_calc_u(nu);
06327             nurbs_knot_calc_v(nu);
06328         }
06329         break;
06330     case CU_PRIM_TUBE:  /* Cylinder */
06331         if( cutype==CU_NURBS ) {
06332             nu= add_nurbs_primitive(C, mat, CU_NURBS|CU_PRIM_CIRCLE, 0);  /* circle */
06333             nu->resolu= cu->resolu;
06334             nu->flag= CU_SMOOTH;
06335             BLI_addtail(editnurb, nu); /* temporal for extrude and translate */
06336             vec[0]=vec[1]= 0.0;
06337             vec[2]= -grid;
06338             
06339             if(newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) {
06340                 /* pass */
06341             }
06342             else {
06343                 mul_mat3_m4_v3(mat, vec);
06344             }
06345 
06346             translateflagNurb(editnurb, 1, vec);
06347             extrudeflagNurb(cu->editnurb, 1);
06348             vec[0]= -2*vec[0]; 
06349             vec[1]= -2*vec[1]; 
06350             vec[2]= -2*vec[2];
06351             translateflagNurb(editnurb, 1, vec);
06352 
06353             BLI_remlink(editnurb, nu);
06354 
06355             a= nu->pntsu*nu->pntsv;
06356             bp= nu->bp;
06357             while(a-- >0) {
06358                 bp->f1 |= SELECT;
06359                 bp++;
06360             }
06361         }
06362         break;
06363     case CU_PRIM_SPHERE:    /* sphere */
06364         if( cutype==CU_NURBS ) {
06365             float tmp_cent[3] = {0.f, 0.f, 0.f};
06366             float tmp_vec[3] = {0.f, 0.f, 1.f};
06367             
06368             nu->pntsu= 5;
06369             nu->pntsv= 1;
06370             nu->orderu= 3;
06371             nu->resolu= cu->resolu;
06372             nu->resolv= cu->resolv;
06373             nu->flag= CU_SMOOTH;
06374             nu->bp= callocstructN(BPoint, 5, "addNurbprim6");
06375             nu->flagu= 0;
06376             bp= nu->bp;
06377 
06378             for(a=0; a<5; a++) {
06379                 bp->f1= SELECT;
06380                 bp->vec[0]+= nurbcircle[a][0]*grid;
06381                 bp->vec[2]+= nurbcircle[a][1]*grid;
06382                 if(a & 1) bp->vec[3]= 0.5*M_SQRT2;
06383                 else bp->vec[3]= 1.0;
06384                 mul_m4_v3(mat,bp->vec);
06385                 bp++;
06386             }
06387             nu->flagu= CU_NURB_BEZIER;
06388             nurbs_knot_calc_u(nu);
06389 
06390             BLI_addtail(editnurb, nu); /* temporal for spin */
06391 
06392             if(newob && (U.flag & USER_ADD_VIEWALIGNED) == 0)   spin_nurb(umat, obedit, tmp_vec, tmp_cent);
06393             else if ((U.flag & USER_ADD_VIEWALIGNED))           spin_nurb(viewmat, obedit, zvec, mat[3]);
06394             else                                                spin_nurb(umat, obedit, tmp_vec, mat[3]);
06395 
06396             nurbs_knot_calc_v(nu);
06397 
06398             a= nu->pntsu*nu->pntsv;
06399             bp= nu->bp;
06400             while(a-- >0) {
06401                 bp->f1 |= SELECT;
06402                 bp++;
06403             }
06404             BLI_remlink(editnurb, nu);
06405         }
06406         break;
06407     case CU_PRIM_DONUT: /* torus */
06408         if( cutype==CU_NURBS ) {
06409             float tmp_cent[3] = {0.f, 0.f, 0.f};
06410             float tmp_vec[3] = {0.f, 0.f, 1.f};
06411             
06412             xzproj= 1;
06413             nu= add_nurbs_primitive(C, mat, CU_NURBS|CU_PRIM_CIRCLE, 0);  /* circle */
06414             xzproj= 0;
06415             nu->resolu= cu->resolu;
06416             nu->resolv= cu->resolv;
06417             nu->flag= CU_SMOOTH;
06418             BLI_addtail(editnurb, nu); /* temporal for spin */
06419 
06420             /* same as above */
06421             if(newob && (U.flag & USER_ADD_VIEWALIGNED) == 0)   spin_nurb(umat, obedit, tmp_vec, tmp_cent);
06422             else if ((U.flag & USER_ADD_VIEWALIGNED))           spin_nurb(viewmat, obedit, zvec, mat[3]);
06423             else                                                spin_nurb(umat, obedit, tmp_vec, mat[3]);
06424 
06425 
06426             BLI_remlink(editnurb, nu);
06427 
06428             a= nu->pntsu*nu->pntsv;
06429             bp= nu->bp;
06430             while(a-- >0) {
06431                 bp->f1 |= SELECT;
06432                 bp++;
06433             }
06434 
06435         }
06436         break;
06437 
06438     default: /* should never happen */
06439         BLI_assert(!"invalid nurbs type");
06440         return NULL;
06441     }
06442 
06443     BLI_assert(nu != NULL);
06444 
06445     if(nu) { /* should always be set */
06446         nu->flag |= CU_SMOOTH;
06447 
06448         test2DNurb(nu);
06449     }
06450 
06451     return nu;
06452 }
06453 
06454 static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
06455 {
06456     Object *obedit= CTX_data_edit_object(C);
06457     ListBase *editnurb;
06458     Nurb *nu;
06459     int newob= 0;
06460     int enter_editmode;
06461     unsigned int layer;
06462     float loc[3], rot[3];
06463     float mat[4][4];
06464 
06465     if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
06466         return OPERATOR_CANCELLED;
06467 
06468     if (!isSurf) { /* adding curve */
06469         if(obedit==NULL || obedit->type!=OB_CURVE) {
06470             Curve *cu;
06471             
06472             obedit= ED_object_add_type(C, OB_CURVE, loc, rot, TRUE, layer);
06473             newob = 1;
06474 
06475             cu= (Curve*)obedit->data;
06476             cu->flag |= CU_DEFORM_FILL;
06477             
06478             if(type & CU_PRIM_PATH)
06479                 cu->flag |= CU_PATH|CU_3D;
06480         } 
06481         else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
06482     } 
06483     else { /* adding surface */
06484         if(obedit==NULL || obedit->type!=OB_SURF) {
06485             obedit= ED_object_add_type(C, OB_SURF, loc, rot, TRUE, layer);
06486             newob = 1;
06487         } 
06488         else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
06489     }
06490 
06491     /* rename here, the undo stack checks name for valid undo pushes */
06492     if(newob) {
06493 
06494         if(obedit->type==OB_CURVE) {
06495             rename_id((ID *)obedit, get_curve_defname(type));
06496             rename_id((ID *)obedit->data, get_curve_defname(type));
06497         }
06498         else {
06499             rename_id((ID *)obedit, get_surf_defname(type));
06500             rename_id((ID *)obedit->data, get_surf_defname(type));
06501         }
06502     }
06503     
06504     /* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */
06505     if(newob && enter_editmode)
06506         ED_undo_push(C, "Enter Editmode");
06507     
06508     ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
06509 
06510     nu= add_nurbs_primitive(C, mat, type, newob);
06511     editnurb= object_editcurve_get(obedit);
06512     BLI_addtail(editnurb, nu);
06513 
06514     /* userdef */
06515     if (newob && !enter_editmode) {
06516         ED_object_exit_editmode(C, EM_FREEDATA);
06517     }
06518 
06519     WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
06520 
06521     return OPERATOR_FINISHED;
06522 }
06523 
06524 static int curve_prim_add(bContext *C, wmOperator *op, int type)
06525 {
06526     return curvesurf_prim_add(C, op, type, 0);
06527 }
06528 
06529 static int surf_prim_add(bContext *C, wmOperator *op, int type)
06530 {
06531     return curvesurf_prim_add(C, op, type, 1);
06532 }
06533 
06534 /* ******************** Curves ******************* */
06535 
06536 static int add_primitive_bezier_exec(bContext *C, wmOperator *op)
06537 {
06538     return curve_prim_add(C, op, CU_BEZIER|CU_PRIM_CURVE);
06539 }
06540 
06541 void CURVE_OT_primitive_bezier_curve_add(wmOperatorType *ot)
06542 {
06543     /* identifiers */
06544     ot->name= "Add Bezier";
06545     ot->description= "Construct a Bezier Curve";
06546     ot->idname= "CURVE_OT_primitive_bezier_curve_add";
06547     
06548     /* api callbacks */
06549     ot->invoke= ED_object_add_generic_invoke;
06550     ot->exec= add_primitive_bezier_exec;
06551     ot->poll= ED_operator_scene_editable;
06552     
06553     /* flags */
06554     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06555 
06556     ED_object_add_generic_props(ot, TRUE);
06557 }
06558 
06559 static int add_primitive_bezier_circle_exec(bContext *C, wmOperator *op)
06560 {
06561     return curve_prim_add(C, op, CU_BEZIER|CU_PRIM_CIRCLE);
06562 }
06563 
06564 void CURVE_OT_primitive_bezier_circle_add(wmOperatorType *ot)
06565 {
06566     /* identifiers */
06567     ot->name= "Add Bezier Circle";
06568     ot->description= "Construct a Bezier Circle";
06569     ot->idname= "CURVE_OT_primitive_bezier_circle_add";
06570     
06571     /* api callbacks */
06572     ot->invoke= ED_object_add_generic_invoke;
06573     ot->exec= add_primitive_bezier_circle_exec;
06574     ot->poll= ED_operator_scene_editable;
06575     
06576     /* flags */
06577     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06578 
06579     ED_object_add_generic_props(ot, TRUE);
06580 }
06581 
06582 static int add_primitive_nurbs_curve_exec(bContext *C, wmOperator *op)
06583 {
06584     return curve_prim_add(C, op, CU_NURBS|CU_PRIM_CURVE);
06585 }
06586 
06587 void CURVE_OT_primitive_nurbs_curve_add(wmOperatorType *ot)
06588 {
06589     /* identifiers */
06590     ot->name= "Add Nurbs Curve";
06591     ot->description= "Construct a Nurbs Curve";
06592     ot->idname= "CURVE_OT_primitive_nurbs_curve_add";
06593     
06594     /* api callbacks */
06595     ot->invoke= ED_object_add_generic_invoke;
06596     ot->exec= add_primitive_nurbs_curve_exec;
06597     ot->poll= ED_operator_scene_editable;
06598     
06599     /* flags */
06600     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06601 
06602     ED_object_add_generic_props(ot, TRUE);
06603 }
06604 
06605 static int add_primitive_nurbs_circle_exec(bContext *C, wmOperator *op)
06606 {
06607     return curve_prim_add(C, op, CU_NURBS|CU_PRIM_CIRCLE);
06608 }
06609 
06610 void CURVE_OT_primitive_nurbs_circle_add(wmOperatorType *ot)
06611 {
06612     /* identifiers */
06613     ot->name= "Add Nurbs Circle";
06614     ot->description= "Construct a Nurbs Circle";
06615     ot->idname= "CURVE_OT_primitive_nurbs_circle_add";
06616     
06617     /* api callbacks */
06618     ot->invoke= ED_object_add_generic_invoke;
06619     ot->exec= add_primitive_nurbs_circle_exec;
06620     ot->poll= ED_operator_scene_editable;
06621     
06622     /* flags */
06623     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06624 
06625     ED_object_add_generic_props(ot, TRUE);
06626 }
06627 
06628 static int add_primitive_curve_path_exec(bContext *C, wmOperator *op)
06629 {
06630     return curve_prim_add(C, op, CU_NURBS|CU_PRIM_PATH);
06631 }
06632 
06633 void CURVE_OT_primitive_nurbs_path_add(wmOperatorType *ot)
06634 {
06635     /* identifiers */
06636     ot->name= "Add Path";
06637     ot->description= "Construct a Path";
06638     ot->idname= "CURVE_OT_primitive_nurbs_path_add";
06639     
06640     /* api callbacks */
06641     ot->invoke= ED_object_add_generic_invoke;
06642     ot->exec= add_primitive_curve_path_exec;
06643     ot->poll= ED_operator_scene_editable;
06644     
06645     /* flags */
06646     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06647 
06648     ED_object_add_generic_props(ot, TRUE);
06649 }
06650 
06651 /* **************** NURBS surfaces ********************** */
06652 static int add_primitive_nurbs_surface_curve_exec(bContext *C, wmOperator *op)
06653 {
06654     return surf_prim_add(C, op, CU_PRIM_CURVE|CU_NURBS);
06655 }
06656 
06657 void SURFACE_OT_primitive_nurbs_surface_curve_add(wmOperatorType *ot)
06658 {
06659     /* identifiers */
06660     ot->name= "Add Surface Curve";
06661     ot->description= "Construct a Nurbs surface Curve";
06662     ot->idname= "SURFACE_OT_primitive_nurbs_surface_curve_add";
06663     
06664     /* api callbacks */
06665     ot->invoke= ED_object_add_generic_invoke;
06666     ot->exec= add_primitive_nurbs_surface_curve_exec;
06667     ot->poll= ED_operator_scene_editable;
06668     
06669     /* flags */
06670     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06671 
06672     ED_object_add_generic_props(ot, TRUE);
06673 }
06674 
06675 static int add_primitive_nurbs_surface_circle_exec(bContext *C, wmOperator *op)
06676 {
06677     return surf_prim_add(C, op, CU_PRIM_CIRCLE|CU_NURBS);
06678 }
06679 
06680 void SURFACE_OT_primitive_nurbs_surface_circle_add(wmOperatorType *ot)
06681 {
06682     /* identifiers */
06683     ot->name= "Add Surface Circle";
06684     ot->description= "Construct a Nurbs surface Circle";
06685     ot->idname= "SURFACE_OT_primitive_nurbs_surface_circle_add";
06686     
06687     /* api callbacks */
06688     ot->invoke= ED_object_add_generic_invoke;
06689     ot->exec= add_primitive_nurbs_surface_circle_exec;
06690     ot->poll= ED_operator_scene_editable;
06691     
06692     /* flags */
06693     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06694 
06695     ED_object_add_generic_props(ot, TRUE);
06696 }
06697 
06698 static int add_primitive_nurbs_surface_surface_exec(bContext *C, wmOperator *op)
06699 {
06700     return surf_prim_add(C, op, CU_PRIM_PATCH|CU_NURBS);
06701 }
06702 
06703 void SURFACE_OT_primitive_nurbs_surface_surface_add(wmOperatorType *ot)
06704 {
06705     /* identifiers */
06706     ot->name= "Add Surface Patch";
06707     ot->description= "Construct a Nurbs surface Patch";
06708     ot->idname= "SURFACE_OT_primitive_nurbs_surface_surface_add";
06709     
06710     /* api callbacks */
06711     ot->invoke= ED_object_add_generic_invoke;
06712     ot->exec= add_primitive_nurbs_surface_surface_exec;
06713     ot->poll= ED_operator_scene_editable;
06714     
06715     /* flags */
06716     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06717 
06718     ED_object_add_generic_props(ot, TRUE);
06719 }
06720 
06721 static int add_primitive_nurbs_surface_cylinder_exec(bContext *C, wmOperator *op)
06722 {
06723     return surf_prim_add(C, op, CU_PRIM_TUBE|CU_NURBS);
06724 }
06725 
06726 void SURFACE_OT_primitive_nurbs_surface_cylinder_add(wmOperatorType *ot)
06727 {
06728     /* identifiers */
06729     ot->name= "Add Surface Cylinder";
06730     ot->description= "Construct a Nurbs surface Cylinder";
06731     ot->idname= "SURFACE_OT_primitive_nurbs_surface_cylinder_add";
06732     
06733     /* api callbacks */
06734     ot->invoke= ED_object_add_generic_invoke;
06735     ot->exec= add_primitive_nurbs_surface_cylinder_exec;
06736     ot->poll= ED_operator_scene_editable;
06737     
06738     /* flags */
06739     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06740 
06741     ED_object_add_generic_props(ot, TRUE);
06742 }
06743 
06744 static int add_primitive_nurbs_surface_sphere_exec(bContext *C, wmOperator *op)
06745 {
06746     return surf_prim_add(C, op, CU_PRIM_SPHERE|CU_NURBS);
06747 }
06748 
06749 void SURFACE_OT_primitive_nurbs_surface_sphere_add(wmOperatorType *ot)
06750 {
06751     /* identifiers */
06752     ot->name= "Add Surface Sphere";
06753     ot->description= "Construct a Nurbs surface Sphere";
06754     ot->idname= "SURFACE_OT_primitive_nurbs_surface_sphere_add";
06755     
06756     /* api callbacks */
06757     ot->invoke= ED_object_add_generic_invoke;
06758     ot->exec= add_primitive_nurbs_surface_sphere_exec;
06759     ot->poll= ED_operator_scene_editable;
06760     
06761     /* flags */
06762     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06763 
06764     ED_object_add_generic_props(ot, TRUE);
06765 }
06766 
06767 static int add_primitive_nurbs_surface_torus_exec(bContext *C, wmOperator *op)
06768 {
06769     return surf_prim_add(C, op, CU_PRIM_DONUT|CU_NURBS);
06770 }
06771 
06772 void SURFACE_OT_primitive_nurbs_surface_torus_add(wmOperatorType *ot)
06773 {
06774     /* identifiers */
06775     ot->name= "Add Surface Torus";
06776     ot->description= "Construct a Nurbs surface Torus";
06777     ot->idname= "SURFACE_OT_primitive_nurbs_surface_torus_add";
06778     
06779     /* api callbacks */
06780     ot->invoke= ED_object_add_generic_invoke;
06781     ot->exec= add_primitive_nurbs_surface_torus_exec;
06782     ot->poll= ED_operator_scene_editable;
06783     
06784     /* flags */
06785     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06786 
06787     ED_object_add_generic_props(ot, TRUE);
06788 }
06789 
06790 /***************** clear tilt operator ********************/
06791 
06792 static int clear_tilt_exec(bContext *C, wmOperator *UNUSED(op))
06793 {
06794     Object *obedit= CTX_data_edit_object(C);
06795     Curve *cu= obedit->data;
06796     ListBase *editnurb= object_editcurve_get(obedit);
06797     Nurb *nu;
06798     BezTriple *bezt;
06799     BPoint *bp;
06800     int a;
06801 
06802     for(nu= editnurb->first; nu; nu= nu->next) {
06803         if( nu->bezt ) {
06804             bezt= nu->bezt;
06805             a= nu->pntsu;
06806             while(a--) {
06807                 if(BEZSELECTED_HIDDENHANDLES(cu, bezt)) bezt->alfa= 0.0;
06808                 bezt++;
06809             }
06810         }
06811         else if(nu->bp) {
06812             bp= nu->bp;
06813             a= nu->pntsu*nu->pntsv;
06814             while(a--) {
06815                 if(bp->f1 & SELECT) bp->alfa= 0.0;
06816                 bp++;
06817             }
06818         }
06819     }
06820 
06821     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
06822     DAG_id_tag_update(obedit->data, 0);
06823 
06824     return OPERATOR_FINISHED;
06825 }
06826 
06827 void CURVE_OT_tilt_clear(wmOperatorType *ot)
06828 {
06829     /* identifiers */
06830     ot->name= "Clear Tilt";
06831     ot->idname= "CURVE_OT_tilt_clear";
06832     
06833     /* api callbacks */
06834     ot->exec= clear_tilt_exec;
06835     ot->poll= ED_operator_editcurve;
06836     
06837     /* flags */
06838     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
06839 }
06840 
06841 /****************** undo for curves ****************/
06842 
06843 static void *undo_check_lastsel(void *lastsel, Nurb *nu, Nurb *newnu)
06844 {
06845     if (nu->bezt) {
06846         BezTriple *lastbezt= (BezTriple*)lastsel;
06847         if (lastbezt >= nu->bezt && lastbezt < nu->bezt + nu->pntsu) {
06848             return newnu->bezt + (lastbezt - nu->bezt);
06849         }
06850     } else {
06851         BPoint *lastbp= (BPoint*)lastsel;
06852         if (lastbp >= nu->bp && lastbp < nu->bp + nu->pntsu*nu->pntsv) {
06853             return newnu->bp + (lastbp - nu->bp);
06854         }
06855     }
06856 
06857     return NULL;
06858 }
06859 
06860 static void undoCurve_to_editCurve(void *ucu, void *obe)
06861 {
06862     Object *obedit= obe;
06863     Curve *cu= (Curve*)obedit->data;
06864     UndoCurve *undoCurve= ucu;
06865     ListBase *undobase= &undoCurve->nubase;
06866     ListBase *editbase= curve_editnurbs(cu);
06867     Nurb *nu, *newnu;
06868     EditNurb *editnurb= cu->editnurb;
06869     void *lastsel= NULL;
06870     AnimData *ad= BKE_animdata_from_id(&cu->id);
06871 
06872     freeNurblist(editbase);
06873 
06874     if (undoCurve->undoIndex) {
06875         BLI_ghash_free(editnurb->keyindex, NULL, (GHashValFreeFP)MEM_freeN);
06876         editnurb->keyindex= dupli_keyIndexHash(undoCurve->undoIndex);
06877     }
06878 
06879     if(ad) {
06880         if(ad->action) {
06881             free_fcurves(&ad->action->curves);
06882             copy_fcurves(&ad->action->curves, &undoCurve->fcurves);
06883         }
06884 
06885         free_fcurves(&ad->drivers);
06886         copy_fcurves(&ad->drivers, &undoCurve->drivers);
06887     }
06888 
06889     /* copy  */
06890     for(nu= undobase->first; nu; nu= nu->next) {
06891         newnu= duplicateNurb(nu);
06892 
06893         if (lastsel == NULL) {
06894             lastsel= undo_check_lastsel(undoCurve->lastsel, nu, newnu);
06895         }
06896 
06897         if (editnurb->keyindex) {
06898             keyIndex_updateNurb(editnurb, nu, newnu);
06899         }
06900 
06901         BLI_addtail(editbase, newnu);
06902     }
06903 
06904     cu->lastsel= lastsel;
06905     cu->actnu= undoCurve->actnu;
06906 
06907     ED_curve_updateAnimPaths(obedit);
06908 }
06909 
06910 static void *editCurve_to_undoCurve(void *obe)
06911 {
06912     Object *obedit= obe;
06913     Curve *cu= (Curve*)obedit->data;
06914     ListBase *nubase= curve_editnurbs(cu);
06915     UndoCurve *undoCurve;
06916     EditNurb *editnurb= cu->editnurb, tmpEditnurb;
06917     Nurb *nu, *newnu;
06918     void *lastsel= NULL;
06919     AnimData *ad= BKE_animdata_from_id(&cu->id);
06920 
06921     undoCurve= MEM_callocN(sizeof(UndoCurve), "undoCurve");
06922 
06923     if (editnurb->keyindex) {
06924         undoCurve->undoIndex= dupli_keyIndexHash(editnurb->keyindex);
06925         tmpEditnurb.keyindex= undoCurve->undoIndex;
06926     }
06927 
06928     if(ad) {
06929         if(ad->action)
06930             copy_fcurves(&undoCurve->fcurves, &ad->action->curves);
06931 
06932         copy_fcurves(&undoCurve->drivers, &ad->drivers);
06933     }
06934 
06935     /* copy  */
06936     for(nu= nubase->first; nu; nu= nu->next) {
06937         newnu= duplicateNurb(nu);
06938 
06939         if (lastsel == NULL) {
06940             lastsel= undo_check_lastsel(cu->lastsel, nu, newnu);
06941         }
06942 
06943         if (undoCurve->undoIndex) {
06944             keyIndex_updateNurb(&tmpEditnurb, nu, newnu);
06945         }
06946 
06947         BLI_addtail(&undoCurve->nubase, newnu);
06948     }
06949 
06950     undoCurve->lastsel= lastsel;
06951     undoCurve->actnu= cu->actnu;
06952 
06953     return undoCurve;
06954 }
06955 
06956 static void free_undoCurve(void *ucv)
06957 {
06958     UndoCurve *undoCurve= ucv;
06959 
06960     freeNurblist(&undoCurve->nubase);
06961 
06962     if(undoCurve->undoIndex)
06963         BLI_ghash_free(undoCurve->undoIndex, NULL, (GHashValFreeFP)MEM_freeN);
06964 
06965     free_fcurves(&undoCurve->fcurves);
06966     free_fcurves(&undoCurve->drivers);
06967 
06968     MEM_freeN(undoCurve);
06969 }
06970 
06971 static void *get_data(bContext *C)
06972 {
06973     Object *obedit= CTX_data_edit_object(C);
06974     return obedit;
06975 }
06976 
06977 /* and this is all the undo system needs to know */
06978 void undo_push_curve(bContext *C, const char *name)
06979 {
06980     undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
06981 }
06982 
06983 void ED_curve_beztcpy(EditNurb *editnurb, BezTriple *dst, BezTriple *src, int count)
06984 {
06985     memcpy(dst, src, count*sizeof(BezTriple));
06986     keyIndex_updateBezt(editnurb, src, dst, count);
06987 }
06988 
06989 void ED_curve_bpcpy(EditNurb *editnurb, BPoint *dst, BPoint *src, int count)
06990 {
06991     memcpy(dst, src, count*sizeof(BPoint));
06992     keyIndex_updateBP(editnurb, src, dst, count);
06993 }
06994 
06995 int ED_curve_actSelection(Curve *cu, float center[3])
06996 {
06997     Nurb *nu= get_lastsel_nurb(cu);
06998 
06999     if(!nu)
07000         return 0;
07001 
07002     if(nu->bezt) {
07003         BezTriple *bezt= cu->lastsel;
07004 
07005         copy_v3_v3(center, bezt->vec[1]);
07006     }
07007     else {
07008         BPoint *bp= cu->lastsel;
07009 
07010         copy_v3_v3(center, bp->vec);
07011     }
07012 
07013     return 1;
07014 }