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