diff options
Diffstat (limited to 'source/blender/src/editcurve.c')
-rw-r--r-- | source/blender/src/editcurve.c | 3979 |
1 files changed, 3979 insertions, 0 deletions
diff --git a/source/blender/src/editcurve.c b/source/blender/src/editcurve.c new file mode 100644 index 00000000000..023fa1bba27 --- /dev/null +++ b/source/blender/src/editcurve.c @@ -0,0 +1,3979 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include <math.h> +#ifndef WIN32 +#include <unistd.h> +#else +#include <io.h> +#include "BLI_winstuff.h" +#endif +#include <stdlib.h> +#include "MEM_guardedalloc.h" + +#include "BMF_Api.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" + +#include "DNA_curve_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_utildefines.h" +#include "BKE_library.h" +#include "BKE_ipo.h" +#include "BKE_displist.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_main.h" + +#include "BIF_gl.h" +#include "BIF_graphics.h" +#include "BIF_screen.h" +#include "BIF_toolbox.h" +#include "BIF_space.h" +#include "BIF_editkey.h" +#include "BIF_mywindow.h" +#include "BIF_interface.h" + +#include "BSE_view.h" /* For persp... */ +#include "BSE_edit.h" + +#include "BDR_drawobject.h" +#include "BDR_editcurve.h" +#include "BDR_editobject.h" + +/* #include "graphics.h" */ +#include "interface.h" /* MAART: for NUM and FLO types, + pupmenu */ +/* #include "edit.h" */ +#include "mydevice.h" +#include "blendef.h" + + +#include "BDR_editcurve.h" +/* still need to eradicate a few :( */ +#define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name) +/* only used sparingly: */ +#define BEZSELECTED(bezt) (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1)) + + +ListBase editNurb; +BPoint *lastselbp; +Nurb *lastnu; /* voor selected */ + + +/* void freeNurblist(ListBase *lb); already declared in the kernel */ + +float nurbcircle[8][2]= { + {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0, 1.0}, + {0.0, 1.0}, { 1.0, 1.0}, { 1.0, 0.0}, { 1.0, -1.0} +}; + +short isNurbsel(Nurb *nu) +{ + BezTriple *bezt; + BPoint *bp; + int a; + + if((nu->type & 7)==CU_BEZIER) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if( (bezt->f1 & 1) || (bezt->f2 & 1) || (bezt->f3 & 1) ) return 1; + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if( (bp->f1 & 1) ) return 1; + bp++; + } + } + return 0; +} + +int isNurbsel_count(Nurb *nu) +{ + BezTriple *bezt; + BPoint *bp; + int a, sel=0; + + if((nu->type & 7)==CU_BEZIER) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if( (bezt->f1 & 1) || (bezt->f2 & 1) || (bezt->f3 & 1) ) sel++; + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if( (bp->f1 & 1) ) sel++; + bp++; + } + } + return sel; +} + + +void printknots() +{ + Nurb *nu; + int a, num; + + nu= editNurb.first; + while(nu) { + if(isNurbsel(nu) && (nu->type & 7)==CU_NURBS) { + if(nu->knotsu) { + num= KNOTSU(nu); + for(a=0;a<num;a++) printf("knotu %d: %f\n", a, nu->knotsu[a]); + } + if(nu->knotsv) { + num= KNOTSV(nu); + for(a=0;a<num;a++) printf("knotv %d: %f\n", a, nu->knotsv[a]); + } + } + nu= nu->next; + } +} + +#if 0 +static void printweightsNurb(void) +{ + Nurb *nu; + BPoint *bp; + int a; + char str[30]; + + if(G.obedit==0) return; + + persp(0); + + glDrawBuffer(GL_FRONT); + + nu= editNurb.first; + while(nu) { + if((nu->type & 7)==CU_NURBS) { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + if(bp->f1 & 1) { + if(bp->s[0]!= 3200) { + sprintf(str,"%2.2f", bp->vec[3]); + + cpack(0x737373); + glRasterPos2i(bp->s[0]-1, bp->s[1]-1); + BMF_DrawString(G.font, str); + + glRasterPos2i(bp->s[0]+1, bp->s[1]+1); + BMF_DrawString(G.font, str); + + cpack(0xFFFFFF); + glRasterPos2i(bp->s[0], bp->s[1]); + BMF_DrawString(G.font, str); + } + } + bp++; + } + } + nu= nu->next; + } + + glDrawBuffer(GL_BACK); + persp(1); +} +#endif + + +/* ********************* LOAD EN MAKE *************** */ + +void load_editNurb() +{ + /* laad editNurb in object */ + Curve *cu= 0; + Nurb *nu, *newnu; + KeyBlock *actkey=0; + + if(G.obedit==0) return; + + if ELEM(G.obedit->type, OB_CURVE, OB_SURF) { + + G.totvert= count_curveverts(&editNurb); + + cu= G.obedit->data; + + /* zijn er keys? */ + if(cu->key) { + actkey= cu->key->block.first; + while(actkey) { + if(actkey->flag & SELECT) break; + actkey= actkey->next; + } + + if(actkey) { + /* aktieve key: de vertices */ + + if(G.totvert) { + if(actkey->data) MEM_freeN(actkey->data); + + actkey->data= MEM_callocN(cu->key->elemsize*G.totvert, "actkey->data"); + actkey->totelem= G.totvert; + + curve_to_key(cu, actkey, &editNurb); + } + } + } + + if(cu->key && actkey!=cu->key->refkey) { + /* er zijn keys, alleen veranderingen in verts schrijven */ + /* als aantal vertices verschillen, beetje onvoorspelbaar */ + + /* vertex -> vertex copy! */ + if(actkey) key_to_curve(actkey, cu, &cu->nurb); + } + else { + freeNurblist(&(cu->nurb)); + + nu= editNurb.first; + while(nu) { + newnu= duplicateNurb(nu); + newnu->hide= 0; + BLI_addtail(&(cu->nurb), newnu); + + if((nu->type & 7)==CU_NURBS) { + if(nu->pntsu < nu->orderu) nu->orderu= nu->pntsu; + } + + nu= nu->next; + } + } + + } + + lastnu= 0; /* voor selected */ + +} + +void make_editNurb() +{ + /* maak kopie van baseNurb in editNurb */ + Curve *cu=0; + Nurb *nu, *newnu; + BezTriple *bezt; + BPoint *bp; + KeyBlock *actkey=0; + int a, tot=0; + + if(G.obedit==0) return; + + lastselbp= 0; /* global voor select row */ + + if ELEM(G.obedit->type, OB_CURVE, OB_SURF) { + freeNurblist(&editNurb); + + cu= G.obedit->data; + nu= cu->nurb.first; + + while(nu) { + newnu= duplicateNurb(nu); + BLI_addtail(&editNurb, newnu); + /* flags op nul */ + newnu->hide= 0; + if((nu->type & 7)==CU_BEZIER) { + a= nu->pntsu; + bezt= newnu->bezt; + while(a--) { + bezt->f1= bezt->f2= bezt->f3= bezt->hide= 0; + bezt++; + tot+= 3; + } + } + else { + a= nu->pntsu*nu->pntsv; + bp= newnu->bp; + while(a--) { + bp->f1= bp->hide= 0; + bp++; + tot++; + } + } + nu= nu->next; + } + + if(cu->key) { + actkey= cu->key->block.first; + while(actkey) { + if(actkey->flag & SELECT) break; + actkey= actkey->next; + } + + if(actkey) { + key_to_curve(actkey, cu, &editNurb); + } + } + makeDispList(G.obedit); + } + else G.obedit= 0; + + countall(); + + lastnu= 0; /* voor selected */ +} + +void remake_editNurb() +{ + + if(okee("Reload Original data")==0) return; + + make_editNurb(); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSEDIT, 0); +} + + +void separate_nurb() +{ + Nurb *nu, *nu1; + Object *oldob; + Base *base, *oldbase; + Curve *cu; + ListBase editnurbo; + float trans[9]; + + if( (G.vd->lay & G.obedit->lay)==0 ) return; + + if(okee("Separate")==0) return; + + waitcursor(1); + + cu= G.obedit->data; + if(cu->key) { + error("Can't separate with vertex keys"); + return; + } + + /* we gaan de zaak als volgt neppen: + * 1. duplicate base: dit wordt de nieuwe, oude pointer onthouden + * 2. alle NIET geselecteerde curves/nurbs apart zetten + * 3. load_ebaseNurb(): dit is de nieuwe base + * 4. freelist en oude nurbs weer terughalen + */ + + /* alleen ebase geselecteerd */ + base= FIRSTBASE; + while(base) { + if(base->lay & G.vd->lay) { + if(base->object==G.obedit) base->flag |= 1; + else base->flag &= ~1; + } + base= base->next; + } + + /* apart zetten: alles wat maar enigszins NIET select is */ + editnurbo.first= editnurbo.last= 0; + nu= editNurb.first; + while(nu) { + nu1= nu->next; + if(isNurbsel(nu)==0) { + BLI_remlink(&editNurb, nu); + BLI_addtail(&editnurbo, nu); + } + nu= nu1; + } + + oldob= G.obedit; + oldbase= BASACT; + + trans[0]=trans[1]=trans[2]=trans[3]=trans[4]=trans[5]= 0.0; + trans[6]=trans[7]=trans[8]= 1.0; + G.qual |= LR_ALTKEY; /* patch om zeker te zijn van gelinkte dupli */ + adduplicate(trans); + G.qual &= ~LR_ALTKEY; + + G.obedit= BASACT->object; /* basact wordt in adduplicate() gezet */ + + G.obedit->data= copy_curve(cu); + /* omdat nieuwe curve een kopie is: aantal users verlagen */ + cu->id.us--; + + load_editNurb(); + + BASACT->flag &= ~SELECT; + + if(editNurb.first) freeNurblist(&editNurb); + + editNurb= editnurbo; + + G.obedit= 0; /* displisten doen anders in editmode */ + makeDispList(OBACT); /* de gesepareerde */ + + G.obedit= oldob; + BASACT= oldbase; + BASACT->flag |= SELECT; + + waitcursor(0); + + countall(); + allqueue(REDRAWVIEW3D, 0); + + lastnu= 0; /* voor selected */ +} + +/* ******************* FLAGS ********************* */ + + +short isNurbselUV(Nurb *nu, int *u, int *v, int flag) +/* +Nurb *nu; +int *u, *v, flag; +*/ +{ + /* return u!=-1: 1 rij in u-richting geselecteerd. U heeft de waarde tussen 0-pntsv + * return v!=-1: 1 kolom in v-richting geselecteerd. V heeft de waarde tussen 0-pntsu + */ + BPoint *bp; + int a, b, sel; + + *u= *v= -1; + + bp= nu->bp; + for(b=0; b<nu->pntsv; b++) { + sel= 0; + for(a=0; a<nu->pntsu; a++, bp++) { + if(bp->f1 & flag) sel++; + } + if(sel==nu->pntsu) { + if(*u== -1) *u= b; + else return 0; + } + else if(sel>1) return 0; /* want sel==1 is nog goed */ + } + + for(a=0; a<nu->pntsu; a++) { + sel= 0; + bp= nu->bp+a; + for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) { + if(bp->f1 & flag) sel++; + } + if(sel==nu->pntsv) { + if(*v== -1) *v= a; + else return 0; + } + else if(sel>1) return 0; + } + + if(*u==-1 && *v>-1) return 1; + if(*v==-1 && *u>-1) return 1; + return 0; +} + +void setflagsNurb(short flag) +/* short flag; */ +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + nu= editNurb.first; + while(nu) { + if( (nu->type & 7)==CU_BEZIER) { + a= nu->pntsu; + bezt= nu->bezt; + while(a--) { + bezt->f1= bezt->f2= bezt->f3= flag; + bezt++; + } + } + else { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + bp->f1= flag; + bp++; + } + } + nu= nu->next; + } +} + +void rotateflagNurb(short flag, float *cent, float rotmat[][3]) +{ + /* alle verts met (flag & 'flag') rotate */ + Nurb *nu; + BPoint *bp; + int a; + + nu= editNurb.first; + while(nu) { + if((nu->type & 7)==CU_NURBS) { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + + while(a--) { + if(bp->f1 & flag) { + bp->vec[0]-=cent[0]; + bp->vec[1]-=cent[1]; + bp->vec[2]-=cent[2]; + Mat3MulVecfl(rotmat, bp->vec); + bp->vec[0]+=cent[0]; + bp->vec[1]+=cent[1]; + bp->vec[2]+=cent[2]; + } + bp++; + } + } + nu= nu->next; + } +} + + +void translateflagNurb(short flag, float *vec) +{ + /* alle verts met (->f & flag) translate */ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + nu= editNurb.first; + while(nu) { + if( (nu->type & 7)==CU_BEZIER) { + a= nu->pntsu; + bezt= nu->bezt; + while(a--) { + if(bezt->f1 & flag) VecAddf(bezt->vec[0], bezt->vec[0], vec); + if(bezt->f2 & flag) VecAddf(bezt->vec[1], bezt->vec[1], vec); + if(bezt->f3 & flag) VecAddf(bezt->vec[2], bezt->vec[2], vec); + bezt++; + } + } + else { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + if(bp->f1 & flag) VecAddf(bp->vec, bp->vec, vec); + bp++; + } + } + + test2DNurb(nu); + + nu= nu->next; + } +} + +void weightflagNurb(short flag, float w, int mode) /* mode==0: vervangen, mode==1: vermenigvuldigen */ +{ + Nurb *nu; + BPoint *bp; + int a; + + nu= editNurb.first; + while(nu) { + if((nu->type & 7)==CU_NURBS) { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + if(bp->f1 & flag) { + if(mode==1) bp->vec[3]*= w; + else bp->vec[3]= w; + } + bp++; + } + } + nu= nu->next; + } +} + +void deleteflagNurb(short flag) +{ + Nurb *nu, *next; + BPoint *bp, *bpn, *newbp; + int a, b, newu, newv, sel; + + if(G.obedit && G.obedit->type==OB_SURF); + else return; + + lastselbp= 0; + + nu= editNurb.first; + while(nu) { + next= nu->next; + + /* is de hele nurb geselecteerd */ + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a) { + a--; + if(bp->f1 & flag); + else break; + bp++; + } + if(a==0) { + BLI_remlink(&editNurb, nu); + freeNurb(nu); + } + else { + /* is de nurb in U richting geselecteerd */ + newv= nu->pntsv; + bp= nu->bp; + for(b=0; b<nu->pntsv; b++) { + sel= 0; + for(a=0; a<nu->pntsu; a++, bp++) { + if(bp->f1 & flag) sel++; + } + if(sel==nu->pntsu) { + newv--; + } + else if(sel>=1) { + /* don't delete */ + break; + } + } + if(newv!=nu->pntsv && b==nu->pntsv) { + /* deleten */ + bp= nu->bp; + bpn = newbp = + (BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb"); + for(b=0; b<nu->pntsv; b++) { + if((bp->f1 & flag)==0) { + memcpy(bpn, bp, nu->pntsu*sizeof(BPoint)); + bpn+= nu->pntsu; + } + bp+= nu->pntsu; + } + nu->pntsv= newv; + MEM_freeN(nu->bp); + nu->bp= newbp; + if(nu->orderv>nu->pntsv) nu->orderv= nu->pntsv; + + makeknots(nu, 2, nu->flagv>>1); + } + else { + /* is de nurb in V richting geselecteerd */ + newu= nu->pntsu; + for(a=0; a<nu->pntsu; a++) { + bp= nu->bp+a; + sel= 0; + for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) { + if(bp->f1 & flag) sel++; + } + if(sel==nu->pntsv) { + newu--; + } + else if(sel>=1) { + /* don't delete */ + break; + } + } + if(newu!=nu->pntsu && a==nu->pntsu) { + /* deleten */ + bp= nu->bp; + bpn = newbp = + (BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb"); + for(b=0; b<nu->pntsv; b++) { + for(a=0; a<nu->pntsu; a++, bp++) { + if((bp->f1 & flag)==0) { + *bpn= *bp; + bpn++; + } + } + } + MEM_freeN(nu->bp); + nu->bp= newbp; + if(newu==1 && nu->pntsv>1) { /* maak een U spline */ + nu->pntsu= nu->pntsv; + nu->pntsv= 1; + SWAP(short, nu->orderu, nu->orderv); + if(nu->orderu>nu->pntsu) nu->orderu= nu->pntsu; + if(nu->knotsv) MEM_freeN(nu->knotsv); + nu->knotsv= 0; + } + else { + nu->pntsu= newu; + if(nu->orderu>nu->pntsu) nu->orderu= nu->pntsu; + } + makeknots(nu, 1, nu->flagu>>1); + } + } + } + nu= next; + } +} + +short extrudeflagNurb(int flag) +/* int flag; */ +{ + Nurb *nu; + BPoint *bp, *bpn, *newbp; + int ok= 0, a, u, v, len; + + if(G.obedit && G.obedit->type==OB_SURF); + else return 0; + + nu= editNurb.first; + while(nu) { + + if(nu->pntsv==1) { + bp= nu->bp; + a= nu->pntsu; + while(a) { + if(bp->f1 & flag); + else break; + bp++; + a--; + } + if(a==0) { + ok= 1; + newbp = + (BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1"); + memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) ); + bp= newbp+ nu->pntsu; + memcpy(bp, nu->bp, nu->pntsu*sizeof(BPoint) ); + MEM_freeN(nu->bp); + nu->bp= newbp; + a= nu->pntsu; + while(a--) { + bp->f1 |= flag; + newbp->f1 &= ~flag; + bp++; + newbp++; + } + + nu->pntsv= 2; + nu->orderv= 2; + makeknots(nu, 2, nu->flagv>>1); + } + } + else { + /* welke rij of kolom is geselecteerd */ + + if( isNurbselUV(nu, &u, &v, flag) ) { + + /* alles deselecteren */ + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + bp->f1 &= ~flag; + bp++; + } + + if(u==0 || u== nu->pntsv-1) { /* rij in u-richting geselecteerd */ + ok= 1; + newbp = + (BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1) + * sizeof(BPoint), "extrudeNurb1"); + if(u==0) { + len= nu->pntsv*nu->pntsu; + memcpy(newbp+nu->pntsu, nu->bp, len*sizeof(BPoint) ); + memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) ); + bp= newbp; + } + else { + len= nu->pntsv*nu->pntsu; + memcpy(newbp, nu->bp, len*sizeof(BPoint) ); + memcpy(newbp+len, nu->bp+len-nu->pntsu, nu->pntsu*sizeof(BPoint) ); + bp= newbp+len; + } + + a= nu->pntsu; + while(a--) { + bp->f1 |= flag; + bp++; + } + + MEM_freeN(nu->bp); + nu->bp= newbp; + nu->pntsv++; + if(nu->resolv<3) nu->resolv++; + makeknots(nu, 2, nu->flagv>>1); + } + else if(v==0 || v== nu->pntsu-1) { /* kolom in v-richting geselecteerd */ + ok= 1; + bpn = newbp = + (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1"); + bp= nu->bp; + + for(a=0; a<nu->pntsv; a++) { + if(v==0) { + *bpn= *bp; + bpn->f1 |= flag; + bpn++; + } + memcpy(bpn, bp, nu->pntsu*sizeof(BPoint)); + bp+= nu->pntsu; + bpn+= nu->pntsu; + if(v== nu->pntsu-1) { + *bpn= *(bp-1); + bpn->f1 |= flag; + bpn++; + } + } + + MEM_freeN(nu->bp); + nu->bp= newbp; + nu->pntsu++; + if(nu->resolu<3) nu->resolu++; + makeknots(nu, 1, nu->flagu>>1); + } + } + } + nu= nu->next; + } + + return ok; +} + + +void adduplicateflagNurb(short flag) +/* short flag; */ +{ + Nurb *nu, *newnu; + BezTriple *bezt, *bezt1; + BPoint *bp, *bp1; + int a, b, starta, enda, newu, newv; + char *usel; + + nu= editNurb.last; + while(nu) { + if( (nu->type & 7)==CU_BEZIER) { + bezt= nu->bezt; + for(a=0; a<nu->pntsu; a++) { + enda= -1; + starta= a; + while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) { + bezt->f1 &= ~flag; + bezt->f2 &= ~flag; + bezt->f3 &= ~flag; + enda=a; + if(a>=nu->pntsu-1) break; + a++; + bezt++; + } + if(enda>=starta) { + newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN"); + memcpy(newnu, nu, sizeof(Nurb)); + BLI_addtail(&editNurb, newnu); + lastnu= newnu; + newnu->pntsu= enda-starta+1; + newnu->bezt= + (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN"); + memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple)); + + b= newnu->pntsu; + bezt1= newnu->bezt; + while(b--) { + bezt1->f1 |= flag; + bezt1->f2 |= flag; + bezt1->f3 |= flag; + bezt1++; + } + + if(nu->flagu & 1) { + if(starta!=0 || enda!=nu->pntsu-1) newnu->flagu--; + } + } + bezt++; + } + } + else if(nu->pntsv==1) { /* want UV Nurb heeft andere duplimethode */ + bp= nu->bp; + for(a=0; a<nu->pntsu; a++) { + enda= -1; + starta= a; + while(bp->f1 & flag) { + bp->f1 &= ~flag; + enda= a; + if(a>=nu->pntsu-1) break; + a++; + bp++; + } + if(enda>=starta) { + newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3"); + memcpy(newnu, nu, sizeof(Nurb)); + lastnu= newnu; + BLI_addtail(&editNurb, newnu); + newnu->pntsu= enda-starta+1; + newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4"); + memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint)); + + b= newnu->pntsu; + bp1= newnu->bp; + while(b--) { + bp1->f1 |= flag; + bp1++; + } + + if(nu->flagu & 1) { + if(starta!=0 || enda!=nu->pntsu-1) newnu->flagu--; + } + + /* knots */ + newnu->knotsu= 0; + makeknots(newnu, 1, newnu->flagu>>1); + } + bp++; + } + } + else { + /* een rechthoekig gebied in de nurb moet geselecteerd zijn */ + if(isNurbsel(nu)) { + usel= MEM_callocN(nu->pntsu, "adduplicateN4"); + bp= nu->bp; + for(a=0; a<nu->pntsv; a++) { + for(b=0; b<nu->pntsu; b++, bp++) { + if(bp->f1 & flag) usel[b]++; + } + } + newu= 0; + newv= 0; + for(a=0; a<nu->pntsu; a++) { + if(usel[a]) { + if(newv==0 || usel[a]==newv) { + newv= usel[a]; + newu++; + } + else { + newv= 0; + break; + } + } + } + if(newu==0 || newv==0) { + printf("Can't duplicate Nurb\n"); + } + else { + + if(newu==1) SWAP(short, newu, newv); + + newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5"); + memcpy(newnu, nu, sizeof(Nurb)); + BLI_addtail(&editNurb, newnu); + lastnu= newnu; + newnu->pntsu= newu; + newnu->pntsv= newv; + newnu->bp = + (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6"); + newnu->orderu= MIN2(nu->orderu, newu); + newnu->orderv= MIN2(nu->orderv, newv); + + bp= newnu->bp; + bp1= nu->bp; + for(a=0; a<nu->pntsv; a++) { + for(b=0; b<nu->pntsu; b++, bp1++) { + if(bp1->f1 & flag) { + memcpy(bp, bp1, sizeof(BPoint)); + bp1->f1 &= ~flag; + bp++; + } + } + } + if(nu->pntsu==newnu->pntsu) { + newnu->knotsu= MEM_mallocN(sizeof(float)*KNOTSU(nu), "adduplicateN6"); + memcpy(newnu->knotsu, nu->knotsu, sizeof(float)*KNOTSU(nu)); + } + else { + newnu->knotsu= 0; + makeknots(newnu, 1, newnu->flagu>>1); + } + if(nu->pntsv==newnu->pntsv) { + newnu->knotsv= MEM_mallocN(sizeof(float)*KNOTSV(nu), "adduplicateN7"); + memcpy(newnu->knotsv, nu->knotsv, sizeof(float)*KNOTSV(nu)); + } + else { + newnu->knotsv= 0; + makeknots(newnu, 2, newnu->flagv>>1); + } + + } + MEM_freeN(usel); + } + } + + nu= nu->prev; + } + + /* lastnu changed */ + allqueue(REDRAWBUTSEDIT, 0); +} + + +void switchdirectionNurb2(void) +{ + Nurb *nu; + + if(G.obedit->lay & G.vd->lay); + else return; + + nu= editNurb.first; + while(nu) { + if( isNurbsel(nu) ) switchdirectionNurb(nu); + nu= nu->next; + } + + makeDispList(G.obedit); + allqueue(REDRAWVIEW3D, 0); +} + +void switchdirection_knots(float *base, int tot) +{ + float *fp1, *fp2, *tempf; + int a; + + if(base==NULL || tot==0) return; + + /* de knots omkeren */ + a= tot; + fp1= base; + fp2= fp1+(a-1); + a/= 2; + while(fp1!=fp2 && a>0) { + SWAP(float, *fp1, *fp2); + a--; + fp1++; + fp2--; + } + /* en weer in stijgende lijn maken */ + a= tot; + fp1= base; + fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect"); + while(a--) { + fp2[0]= fabs(fp1[1]-fp1[0]); + fp1++; + fp2++; + } + + a= tot-1; + fp1= base; + fp2= tempf; + fp1[0]= 0.0; + fp1++; + while(a--) { + fp1[0]= fp1[-1]+fp2[0]; + fp1++; + fp2++; + } + MEM_freeN(tempf); +} + +/* **************** EDIT ************************ */ + +void deselectall_nurb() +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a, b; + + if(G.obedit->lay & G.vd->lay); + else return; + + a= 0; + nu= editNurb.first; + while(nu) { + if((nu->type & 7)==CU_BEZIER) { + b= nu->pntsu; + bezt= nu->bezt; + while(b--) { + if(bezt->hide==0) { + if(bezt->f1 & 1) { + a=1; + break; + } + if(bezt->f2 & 1) { + a=1; + break; + } + if(bezt->f3 & 1) { + a=1; + break; + } + } + bezt++; + } + } + else { + b= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(b--) { + if(bp->hide==0) { + if(bp->f1 & 1) { + a=1; + break; + } + } + bp++; + } + } + if(a) break; + nu= nu->next; + } + + nu= editNurb.first; + while(nu) { + if((nu->type & 7)==1) { + b= nu->pntsu; + bezt= nu->bezt; + while(b--) { + if(bezt->hide==0) { + if(a) { + bezt->f1 &= ~1; + bezt->f2 &= ~1; + bezt->f3 &= ~1; + } + else { + bezt->f1 |= 1; + bezt->f2 |= 1; + bezt->f3 |= 1; + } + } + bezt++; + } + } + else { + b= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(b--) { + if(bp->hide==0) { + if(a) bp->f1 &= ~ 1; + else bp->f1 |= 1; + } + bp++; + } + } + nu= nu->next; + } + countall(); + allqueue(REDRAWVIEW3D, 0); +} + +void hideNurb(int swap) +{ + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int a, sel; + + if(G.obedit==0) return; + + nu= editNurb.first; + while(nu) { + if((nu->type & 7)==CU_BEZIER) { + bezt= nu->bezt; + a= nu->pntsu; + sel= 0; + while(a--) { + if(BEZSELECTED(bezt)) { + sel++; + bezt->f1 &= ~1; + bezt->f2 &= ~1; + bezt->f3 &= ~1; + bezt->hide= 1; + } + bezt++; + } + if(sel==nu->pntsu) nu->hide= 1; + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + sel= 0; + while(a--) { + if(swap==0 && (bp->f1 & 1)) { + bp->f1 &= ~1; + bp->hide= 1; + sel++; + } + else if(swap && (bp->f1 & 1)==0) { + bp->f1 &= ~1; + bp->hide= 1; + sel++; + } + bp++; + } + if(sel==nu->pntsu*nu->pntsv) nu->hide= 1; + } + nu= nu->next; + } + + makeDispList(G.obedit); + countall(); + allqueue(REDRAWVIEW3D, 0); +} + +void revealNurb() +{ + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int a; + + if(G.obedit==0) return; + + nu= editNurb.first; + while(nu) { + nu->hide= 0; + if((nu->type & 7)==CU_BEZIER) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt->hide) { + bezt->f1 |= 1; + bezt->f2 |= 1; + bezt->f3 |= 1; + bezt->hide= 0; + } + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if(bp->hide) { + bp->f1 |= 1; + bp->hide= 0; + } + bp++; + } + } + nu= nu->next; + } + + makeDispList(G.obedit); + countall(); + allqueue(REDRAWVIEW3D, 0); +} + +void selectswapNurb() +{ + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int a; + + if(G.obedit==0) return; + + nu= editNurb.first; + while(nu) { + if((nu->type & 7)==CU_BEZIER) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt->hide==0) { + if(bezt->f1 & 1) bezt->f1 &= ~1; + else bezt->f1 |= 1; + if(bezt->f2 & 1) bezt->f2 &= ~1; + else bezt->f2 |= 1; + if(bezt->f3 & 1) bezt->f3 &= ~1; + else bezt->f3 |= 1; + } + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if(bp->hide==0) { + if(bp->f1 & 1) bp->f1 &= ~1; + else bp->f1 |= 1; + } + bp++; + } + } + nu= nu->next; + } + + countall(); + allqueue(REDRAWVIEW3D, 0); +} + +/** Divide the line segments associated with the currently selected + * curve nodes (Bezier or NURB). If there are no valid segment + * selections within the current selection, nothing happens. + * + * @deffunc subdividenurb subdivideNurb(void) + * @return Nothing + * @param None +*/ +void subdivideNurb() +{ + Nurb *nu; + BezTriple *prevbezt, *bezt, *beztnew, *beztn; + BPoint *bp, *prevbp, *bpnew, *bpn; + float vec[12]; + int a, b, sel, aantal, *usel, *vsel; + + // printf("*** subdivideNurb: entering subdivide\n"); + + nu= editNurb.first; + while(nu) { + aantal= 0; + if((nu->type & 7)==CU_BEZIER) { + /* + Insert a point into a 2D Bezier curve. + Endpoints are preserved. Otherwise, all selected and inserted points are + newly created. Old points are discarded. + */ + /* tellen */ + if(nu->flagu & 1) { + a= nu->pntsu; + bezt= nu->bezt; + prevbezt= bezt+(a-1); + } + else { + a= nu->pntsu-1; + prevbezt= nu->bezt; + bezt= prevbezt+1; + } + while(a--) { + if( BEZSELECTED(prevbezt) && BEZSELECTED(bezt) ) aantal++; + prevbezt= bezt; + bezt++; + } + + if(aantal) { + /* inserten */ + beztnew = + /* I have some severe doubt about the original + * formulation... I stick to the upper bound to be + * on the safe side */ + (BezTriple*)MEM_mallocN((aantal + nu->pntsu) * sizeof(BezTriple), "subdivNurb"); +/* mallocstructN(BezTriple, aantal+nu->pntsu, "subdivNurb"); */ + beztn= beztnew; + if(nu->flagu & 1) { + a= nu->pntsu; + bezt= nu->bezt; + prevbezt= bezt+(a-1); + } + else { + a= nu->pntsu-1; + prevbezt= nu->bezt; + bezt= prevbezt+1; + } + while(a--) { + memcpy(beztn, prevbezt, sizeof(BezTriple)); + beztn++; + // printf("*** subdivideNurb: insert Bezier point\n"); + + if( BEZSELECTED(prevbezt) && BEZSELECTED(bezt) ) { + memcpy(beztn, bezt, sizeof(BezTriple)); + maakbez(prevbezt->vec[1][0],prevbezt->vec[2][0], + bezt->vec[0][0],bezt->vec[1][0],vec,2); + maakbez(prevbezt->vec[1][1],prevbezt->vec[2][1], + bezt->vec[0][1],bezt->vec[1][1],vec+1,2); + maakbez(prevbezt->vec[1][2],prevbezt->vec[2][2], + bezt->vec[0][2],bezt->vec[1][2],vec+2,2); + VECCOPY(beztn->vec[1], vec+3); + beztn->h1= beztn->h2= HD_AUTO; + beztn++; + } + + prevbezt= bezt; + bezt++; + } + /* laatste punt */ + if((nu->flagu & 1)==0) memcpy(beztn, prevbezt, sizeof(BezTriple)); + + MEM_freeN(nu->bezt); + nu->bezt= beztnew; + nu->pntsu+= aantal; + + calchandlesNurb(nu); + } + } /* End of 'if((nu->type & 7)==CU_BEZIER)' */ + else if (nu->pntsv==1) { + /* + All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves + are handled together with the regular NURB plane division, as it + should be. I split it off just now, let's see if it is + stable... nzc 30-5-'00 + */ + /* tellen */ + if(nu->flagu & 1) { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + prevbp= bp+(a-1); + } + else { + a= nu->pntsu-1; + prevbp= nu->bp; + bp= prevbp+1; + } + while(a--) { + if( (bp->f1 & 1) && (prevbp->f1 & 1) ) aantal++; + prevbp= bp; + bp++; + } + + if(aantal) { + /* inserten */ + bpnew = + (BPoint*)MEM_mallocN((aantal + nu->pntsu) * sizeof(BPoint), "subdivNurb2"); + bpn= bpnew; + + if(nu->flagu & 1) { + a= nu->pntsu; + bp= nu->bp; + prevbp= bp+(a-1); + } + else { + a= nu->pntsu-1; + prevbp= nu->bp; + bp= prevbp+1; + } + while(a--) { + memcpy(bpn, prevbp, sizeof(BPoint)); + bpn++; + + if( (bp->f1 & 1) && (prevbp->f1 & 1) ) { + // printf("*** subdivideNurb: insert 'linear' point\n"); + memcpy(bpn, bp, sizeof(BPoint)); + bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0; + bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0; + bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0; + bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0; + bpn++; + + } + prevbp= bp; + bp++; + } + if((nu->flagu & 1)==0) memcpy(bpn, prevbp, sizeof(BPoint)); /* laatste punt */ + + MEM_freeN(nu->bp); + nu->bp= bpnew; + nu->pntsu+= aantal; + + if(nu->type & 4) { + makeknots(nu, 1, nu->flagu>>1); + } + } + } /* End of 'else if(nu->pntsv==1)' */ + else if((nu->type & 7)==CU_NURBS) { + /* This is a very strange test ... */ + /** + Subdivide NURB surfaces - nzc 30-5-'00 - + + Subdivision of a NURB curve can be effected by adding a + control point (insertion of a knot), or by raising the + degree of the functions used to build the NURB. The + expression + + degree = #knots - #controlpoints + 1 (J Walter piece) + degree = #knots - #controlpoints (Blender + implementation) + ( this is confusing.... what is true? Another concern + is that the JW piece allows the curve to become + explicitly 1st order derivative discontinuous, while + this is not what we want here... ) + + is an invariant for a single NURB curve. Raising the degree + of the NURB is done elsewhere; the degree is assumed + constant during this opration. Degree is a property shared + by all controlpoints in a curve (even though it is stored + per control point - this can be misleading). + Adding a knot is done by searching for the place in the + knot vector where a certain knot value must be inserted, or + by picking an appropriate knot value between two existing + ones. The number of controlpoints that is influenced by the + insertion depends on the order of the curve. A certain + minimum number of knots is needed to form high-order + curves, as can be seen from the equation above. In Blender, + currently NURBs may be up to 6th order, so we modify at + most 6 points. One point is added. For an n-degree curve, + n points are discarded, and n+1 points inserted + (so effectively, n points are modified). (that holds for + the JW piece, but it seems not for our NURBs) + In practice, the knot spacing is copied, but the tail + (the points following the insertion point) need to be + offset to keep the knot series ascending. The knot series + is always a series of monotonically ascending integers in + Blender. When not enough control points are available to + fit the order, duplicates of the endpoints are added as + needed. + */ + /* selecteer-arrays aanleggen */ + usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3"); + vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3"); + sel= 0; + + /* Count the number of selected points. */ + bp= nu->bp; + for(a=0; a<nu->pntsv; a++) { + for(b=0; b<nu->pntsu; b++) { + if(bp->f1 & 1) { + usel[b]++; + vsel[a]++; + sel++; + } + bp++; + } + } + if( sel == (nu->pntsu*nu->pntsv) ) { /* hele nurb subdividen */ + /* Global subdivision is a special case of partial + subdivision. Strange it is considered separately... */ + bpn=bpnew= MEM_mallocN( (2*nu->pntsu-1)*(2*nu->pntsv-1)*sizeof(BPoint), "subdivideNurb4"); + bp= nu->bp; + /* eerst de rijen subdividen */ + for(a=0; a<nu->pntsv; a++) { + for(b=0; b<nu->pntsu; b++) { + *bpn= *bp; + bpn++; + bp++; + if(b<nu->pntsu-1) { + *bpn= *bp; + prevbp= bp-1; + bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0; + bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0; + bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0; + bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0; + bpn++; + } + } + bpn+= (2*nu->pntsu-1); + } + /* nu nieuwe invoegen */ + bpn= bpnew+(2*nu->pntsu-1); + bp= bpnew+(4*nu->pntsu-2); + prevbp= bpnew; + for(a=1; a<nu->pntsv; a++) { + + for(b=0; b<2*nu->pntsu-1; b++) { + *bpn= *bp; + bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0; + bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0; + bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0; + bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0; + bpn++; + bp++; + prevbp++; + } + bp+= (2*nu->pntsu-1); + bpn+= (2*nu->pntsu-1); + prevbp+= (2*nu->pntsu-1); + } + MEM_freeN(nu->bp); + nu->bp= bpnew; + nu->pntsu= 2*nu->pntsu-1; + nu->pntsv= 2*nu->pntsv-1; + makeknots(nu, 1, nu->flagu>>1); + makeknots(nu, 2, nu->flagv>>1); + } /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */ + else { + /* in v richting subdividen? */ + sel= 0; + for(a=0; a<nu->pntsv-1; a++) { + if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel++; + } + + if(sel) { /* V ! */ + bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4"); + bp= nu->bp; + for(a=0; a<nu->pntsv; a++) { + for(b=0; b<nu->pntsu; b++) { + *bpn= *bp; + bpn++; + bp++; + } + if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) { + prevbp= bp- nu->pntsu; + for(b=0; b<nu->pntsu; b++) { + /* + This simple bisection must be replaces by a + subtle resampling of a number of points. Our + task is made slightly easier because each + point in our curve is a separate data + node. (is it?) + */ + *bpn= *prevbp; + bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0; + bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0; + bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0; + bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0; + bpn++; + prevbp++; + bp++; + } + bp-= nu->pntsu; + } + } + MEM_freeN(nu->bp); + nu->bp= bpnew; + nu->pntsv+= sel; + makeknots(nu, 2, nu->flagv>>1); + } + else { + /* of in u richting? */ + sel= 0; + for(a=0; a<nu->pntsu-1; a++) { + if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel++; + } + + if(sel) { /* U ! */ + /* Inserting U points is sort of 'default' Flat curves only get */ + /* U points inserted in them. */ + bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4"); + bp= nu->bp; + for(a=0; a<nu->pntsv; a++) { + for(b=0; b<nu->pntsu; b++) { + *bpn= *bp; + bpn++; + bp++; + if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) { + /* + One thing that bugs me here is that the + orders of things are not the same as in + the JW piece. Also, this implies that we + handle at most 3rd order curves? I miss + some symmetry here... + */ + prevbp= bp- 1; + *bpn= *prevbp; + bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0; + bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0; + bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0; + bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0; + bpn++; + } + } + } + MEM_freeN(nu->bp); + nu->bp= bpnew; + nu->pntsu+= sel; + makeknots(nu, 1, nu->flagu>>1); /* shift knots + forward */ + } + } + } + MEM_freeN(usel); + MEM_freeN(vsel); + // printf("*** subdivideNurb: end of NURB splitting part\n"); + } /* End of 'if((nu->type & 7)==CU_NURBS)' */ + nu= nu->next; + } + + /* Sync flushing */ + // printf("*** subdivideNurb: subdivide done\n"); + + makeDispList(G.obedit); + countall(); + allqueue(REDRAWVIEW3D, 0); +} + + +short findnearestNurbvert(short sel, Nurb **nurb, BezTriple **bezt, BPoint **bp) +/* +short sel; +Nurb **nurb; +BezTriple **bezt; +BPoint **bp; +*/ +{ + /* sel==1: selected krijgen een nadeel */ + /* in nurb en bezt of bp wordt nearest weggeschreven */ + /* return 0 1 2: handlepunt */ + Nurb *nu; + BezTriple *bezt1; + BPoint *bp1; + short dist= 100, temp, mval[2], a, hpoint=0; + + *nurb= 0; + *bezt= 0; + *bp= 0; + + /* projektie doen */ + calc_nurbverts_ext(); /* drawobject.c */ + + getmouseco_areawin(mval); + + nu= editNurb.first; + while(nu) { + if((nu->type & 7)==CU_BEZIER) { + bezt1= nu->bezt; + a= nu->pntsu; + while(a--) { + if(bezt1->hide==0) { + temp= abs(mval[0]- bezt1->s[0][0])+ abs(mval[1]- bezt1->s[0][1]); + if( (bezt1->f1 & 1)==sel) temp+=5; + if(temp<dist) { + hpoint=0; + *bezt=bezt1; + dist= temp; + *nurb= nu; + *bp= 0; + } + + /* middelste punten een klein nadeel */ + temp= 3+abs(mval[0]- bezt1->s[1][0])+ abs(mval[1]- bezt1->s[1][1]); + if( (bezt1->f2 & 1)==sel) temp+=5; + if(temp<dist) { + hpoint=1; + *bezt=bezt1; + dist= temp; + *nurb= nu; + *bp= 0; + } + + temp= abs(mval[0]- bezt1->s[2][0])+ abs(mval[1]- bezt1->s[2][1]); + if( (bezt1->f3 & 1)==sel) temp+=5; + if(temp<dist) { + hpoint=2; + *bezt=bezt1; + dist= temp; + *nurb= nu; + *bp= 0; + } + } + bezt1++; + } + } + else { + bp1= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if(bp1->hide==0) { + temp= abs(mval[0]- bp1->s[0])+ abs(mval[1]- bp1->s[1]); + if( (bp1->f1 & 1)==sel) temp+=5; + if(temp<dist) { + hpoint=0; + *bp=bp1; + dist= temp; + *nurb= nu; + *bezt= 0; + } + } + bp1++; + } + } + nu= nu->next; + } + + return hpoint; +} + + +void findselectedNurbvert(Nurb **nu, BezTriple **bezt, BPoint **bp) +{ + /* in nu en (bezt of bp) wordt selected weggeschreven als er 1 sel. is */ + /* als er meer punten in 1 spline selected: alleen nu terug, bezt en bp zijn 0 */ + Nurb *nu1; + BezTriple *bezt1; + BPoint *bp1; + int a; + + *nu= 0; + *bezt= 0; + *bp= 0; + nu1= editNurb.first; + while(nu1) { + if((nu1->type & 7)==CU_BEZIER) { + bezt1= nu1->bezt; + a= nu1->pntsu; + while(a--) { + if( (bezt1->f1 & 1) || (bezt1->f2 & 1) || (bezt1->f3 & 1) ) { + if(*nu!=0 && *nu!= nu1) { + *nu= 0; + *bp= 0; + *bezt= 0; + return; + } + else if(*bezt || *bp) { + *bp= 0; + *bezt= 0; + } + else { + *bezt= bezt1; + *nu= nu1; + } + } + bezt1++; + } + } + else { + bp1= nu1->bp; + a= nu1->pntsu*nu1->pntsv; + while(a--) { + if( bp1->f1 & 1 ) { + if(*nu!=0 && *nu!= nu1) { + *bp= 0; + *bezt= 0; + *nu= 0; + return; + } + else if(*bezt || *bp) { + *bp= 0; + *bezt= 0; + } + else { + *bp= bp1; + *nu= nu1; + } + } + bp1++; + } + } + nu1= nu1->next; + } +} + +void setsplinetype(short type) +/* +short type; +*/ +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a, c, nr; + + if(type==CU_CARDINAL || type==CU_BSPLINE) { + error("Not implemented yet"); + return; + } + + nu= editNurb.first; + while(nu) { + if(isNurbsel(nu)) { + + if((nu->type & 7)==0) { /* Poly */ + if(type==CU_BEZIER) { /* naar Bezier met vecthandles */ + nr= nu->pntsu; + bezt = + (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2"); + nu->bezt= bezt; + a= nr; + bp= nu->bp; + while(a--) { + VECCOPY(bezt->vec[1], bp->vec); + bezt->f1=bezt->f2=bezt->f3= bp->f1; + bezt->h1= bezt->h2= HD_VECT; + bp++; + bezt++; + } + MEM_freeN(nu->bp); + nu->bp= 0; + nu->pntsu= nr; + nu->type &= ~7; + nu->type |= 1; + calchandlesNurb(nu); + } + else if(type==4) { /* naar Nurb */ + nu->type &= ~7; + nu->type+= 4; + nu->orderu= 4; + nu->flagu &= 1; + nu->flagu += 4; + makeknots(nu, 1, nu->flagu>>1); + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + bp->vec[3]= 1.0; + bp++; + } + } + } + else if((nu->type & 7)==CU_BEZIER) { /* Bezier */ + if(type==0 || type==4) { /* naar Poly of Nurb */ + nr= 3*nu->pntsu; + nu->bp = + (BPoint*)MEM_callocN(nr * sizeof(BPoint), "setsplinetype"); + a= nu->pntsu; + bezt= nu->bezt; + bp= nu->bp; + while(a--) { + if(type==0 && bezt->h1==HD_VECT && bezt->h2==HD_VECT) { + /* vectorhandle wordt 1 polyvert */ + VECCOPY(bp->vec, bezt->vec[1]); + bp->vec[3]= 1.0; + bp->f1= bezt->f2; + nr-= 2; + bp++; + } + else { + for(c=0;c<3;c++) { + VECCOPY(bp->vec, bezt->vec[c]); + bp->vec[3]= 1.0; + if(c==0) bp->f1= bezt->f1; + else if(c==1) bp->f1= bezt->f2; + else bp->f1= bezt->f3; + bp++; + } + } + bezt++; + } + MEM_freeN(nu->bezt); + nu->bezt= 0; + nu->pntsu= nr; + nu->pntsv= 1; + nu->orderu= 4; + nu->orderv= 1; + nu->type &= ~7; + nu->type+= type; + if(nu->flagu & 1) c= nu->orderu-1; + else c= 0; + if(type== 4) { + nu->flagu &= 1; + nu->flagu += 4; + makeknots(nu, 1, nu->flagu>>1); + } + } + } + else if( (nu->type & 7)==CU_NURBS && G.obedit->type==OB_CURVE) { + if(type==0) { /* naar Poly */ + nu->type &= ~7; + MEM_freeN(nu->knotsu); + nu->knotsu= 0; + if(nu->knotsv) MEM_freeN(nu->knotsv); + nu->knotsv= 0; + } + else if(type==CU_BEZIER) { /* naar Bezier */ + nr= nu->pntsu/3; + bezt = + (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2"); + nu->bezt= bezt; + a= nr; + bp= nu->bp; + while(a--) { + VECCOPY(bezt->vec[0], bp->vec); + bezt->f1= bp->f1; + bp++; + VECCOPY(bezt->vec[1], bp->vec); + bezt->f2= bp->f1; + bp++; + VECCOPY(bezt->vec[2], bp->vec); + bezt->f3= bp->f1; + bp++; + bezt++; + } + MEM_freeN(nu->bp); + nu->bp= 0; + MEM_freeN(nu->knotsu); + nu->knotsu= 0; + nu->pntsu= nr; + nu->type &= ~7; + nu->type+= 1; + } + } + } + nu= nu->next; + } +} + +/* ******************** SKINNING LOFTING!!! ******************** */ + +void rotate_direction_nurb(Nurb *nu) +{ + BPoint *bp1, *bp2, *temp; + int u, v; + + SWAP(short, nu->pntsu, nu->pntsv); + SWAP(short, nu->orderu, nu->orderv); + SWAP(short, nu->resolu, nu->resolv); + SWAP(short, nu->flagu, nu->flagv); + + SWAP(float *, nu->knotsu, nu->knotsv); + switchdirection_knots(nu->knotsv, KNOTSV(nu) ); + + temp= MEM_dupallocN(nu->bp); + bp1= nu->bp; + for(v=0; v<nu->pntsv; v++) { + for(u=0; u<nu->pntsu; u++, bp1++) { + bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v; + *bp1= *bp2; + } + } + + MEM_freeN(temp); +} + +int is_u_selected(Nurb *nu, int u) +{ + BPoint *bp; + int v; + + /* what about resolu == 2? */ + bp= nu->bp+u; + for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) { + if(v) if(bp->f1 & 1) return 1; + } + + return 0; +} + +/* ******************************** */ + +typedef struct NurbSort { + struct NurbSort *next, *prev; + Nurb *nu; + float vec[3]; +} NurbSort; + +static ListBase nsortbase= {0, 0}; +/* static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */ + +void make_selection_list_nurb() +{ + ListBase nbase= {0, 0}; + NurbSort *nus, *nustest, *headdo, *taildo; + Nurb *nu; + BPoint *bp; + float dist, headdist, taildist; + int a; + + nu= editNurb.first; + while(nu) { + if( isNurbsel(nu) ) { + + nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort"); + BLI_addhead(&nbase, nus); + nus->nu= nu; + + bp= nu->bp; + a= nu->pntsu; + while(a--) { + VecAddf(nus->vec, nus->vec, bp->vec); + bp++; + } + VecMulf(nus->vec, 1.0/(float)nu->pntsu); + + + } + nu= nu->next; + } + + /* just add the first one */ + nus= nbase.first; + BLI_remlink(&nbase, nus); + BLI_addtail( &nsortbase, nus); + + /* now add, either at head or tail, the closest one */ + while(nbase.first) { + + headdist= taildist= 1.0e30; + headdo= taildo= 0; + + nustest= nbase.first; + while(nustest) { + dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.first)->vec); + + if(dist<headdist) { + headdist= dist; + headdo= nustest; + } + dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.last)->vec); + + if(dist<taildist) { + taildist= dist; + taildo= nustest; + } + nustest= nustest->next; + } + + if(headdist<taildist) { + BLI_remlink(&nbase, headdo); + BLI_addhead(&nsortbase, headdo); + } + else { + BLI_remlink(&nbase, taildo); + BLI_addtail(&nsortbase, taildo); + } + } +} + +void merge_2_nurb(Nurb *nu1, Nurb *nu2) +{ + BPoint *bp, *bp1, *bp2, *temp; + float len1, len2; + int origu, u, v; + + /* first nurbs will be changed to make u = resolu-1 selected */ + /* 2nd nurbs will be changed to make u = 0 selected */ + + /* first nurbs: u = resolu-1 selected */ + + if( is_u_selected(nu1, nu1->pntsu-1) ); + else { + rotate_direction_nurb(nu1); + if( is_u_selected(nu1, nu1->pntsu-1) ); + else { + rotate_direction_nurb(nu1); + if( is_u_selected(nu1, nu1->pntsu-1) ); + else { + rotate_direction_nurb(nu1); + if( is_u_selected(nu1, nu1->pntsu-1) ); + else { + /* rotate again, now its OK! */ + if(nu1->pntsv!=1) rotate_direction_nurb(nu1); + return; + } + } + } + } + + /* 2nd nurbs: u = 0 selected */ + if( is_u_selected(nu2, 0) ); + else { + rotate_direction_nurb(nu2); + if( is_u_selected(nu2, 0) ); + else { + rotate_direction_nurb(nu2); + if( is_u_selected(nu2, 0) ); + else { + rotate_direction_nurb(nu2); + if( is_u_selected(nu2, 0) ); + else { + /* rotate again, now its OK! */ + if(nu1->pntsu==1) rotate_direction_nurb(nu1); + if(nu2->pntsv!=1) rotate_direction_nurb(nu2); + return; + } + } + } + } + + if( nu1->pntsv != nu2->pntsv ) { + error("resolution doesn't match"); + return; + } + + /* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */ + /* maybe we need a 'v' flip of nu2? */ + + bp1= nu1->bp+nu1->pntsu-1; + bp2= nu2->bp; + len1= 0.0; + + for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) { + len1+= VecLenf(bp1->vec, bp2->vec); + } + + bp1= nu1->bp + nu1->pntsu-1; + bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1); + len2= 0.0; + + for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) { + len2+= VecLenf(bp1->vec, bp2->vec); + } + + /* merge */ + origu= nu1->pntsu; + nu1->pntsu+= nu2->pntsu; + nu1->resolu+= nu2->pntsu; + if(nu1->resolv < nu2->resolv) nu1->resolv= nu2->resolv; + if(nu1->orderu<3) nu1->orderu++; + if(nu1->orderv<3) nu1->orderv++; + temp= nu1->bp; + nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP"); + + bp= nu1->bp; + bp1= temp; + + for(v=0; v<nu1->pntsv; v++) { + + /* switch direction? */ + if(len1<len2) bp2= nu2->bp + v*nu2->pntsu; + else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu; + + for(u=0; u<nu1->pntsu; u++, bp++) { + if(u<origu) { + *bp= *bp1; bp1++; + bp->f1 &= ~SELECT; + } + else { + *bp= *bp2; bp2++; + } + } + } + + /* merge knots */ + makeknots(nu1, 1, nu1->flagu>>1); + + /* make knots, for merged curved for example */ + makeknots(nu1, 2, nu1->flagv>>1); + + MEM_freeN(temp); + BLI_remlink(&editNurb, nu2); + freeNurb(nu2); +} + +void merge_nurb() +{ + NurbSort *nus1, *nus2; + int ok= 1; + + make_selection_list_nurb(); + + if(nsortbase.first == nsortbase.last) { + BLI_freelistN(&nsortbase); + error("Too few selections"); + return; + } + + nus1= nsortbase.first; + nus2= nus1->next; + + /* resolution match, to avoid uv rotations */ + if(nus1->nu->pntsv==1) { + if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv); + else ok= 0; + } + else if(nus2->nu->pntsv==1) { + if(nus2->nu->pntsu==nus1->nu->pntsu || nus2->nu->pntsu==nus1->nu->pntsv); + else ok= 0; + } + else if( nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsv==nus2->nu->pntsv); + else if( nus1->nu->pntsu==nus2->nu->pntsv || nus1->nu->pntsv==nus2->nu->pntsu); + else { + ok= 0; + } + + if(ok==0) { + error("resolution doesn't match"); + BLI_freelistN(&nsortbase); + return; + } + + while(nus2) { + merge_2_nurb(nus1->nu, nus2->nu); + nus2= nus2->next; + } + + BLI_freelistN(&nsortbase); + + makeDispList(G.obedit); + allqueue(REDRAWVIEW3D, 0); + +} + + +void addsegment_nurb() +{ + /* voegt twee curves samen */ + Nurb *nu, *nu1=0, *nu2=0; + BezTriple *bezt; + BPoint *bp; + float *fp, offset; + int a; + + /* first decide if this is a surface merge! */ + if(G.obedit->type==OB_SURF) nu= editNurb.first; + else nu= 0; + + while(nu) { + if( isNurbsel(nu) ) { + + if(nu->pntsu>1 && nu->pntsv>1) break; + if(isNurbsel_count(nu)>1) break; + if(isNurbsel_count(nu)==1) { + /* only 1 selected, not first or last, a little complex, but intuitive */ + if(nu->pntsv==1) { + if( (nu->bp->f1 & 1) || ((nu->bp+nu->pntsu-1)->f1 & 1)); + else break; + } + } + } + nu= nu->next; + } + if(nu) { + merge_nurb(); + return; + } + + /* vind de beide nurben en punten, nu1 wordt achter nu2 gezet */ + nu= editNurb.first; + while(nu) { + if((nu->flagu & 1)==0) { /* niet cyclic */ + if( (nu->type & 7)==CU_BEZIER ) { + bezt= nu->bezt; + if(nu1==0) { + if( BEZSELECTED(bezt) ) nu1= nu; + else { + bezt= bezt+(nu->pntsu-1); + if( BEZSELECTED(bezt) ) { + nu1= nu; + switchdirectionNurb(nu); + } + } + } + else if(nu2==0) { + if( BEZSELECTED(bezt) ) { + nu2= nu; + switchdirectionNurb(nu); + } + else { + bezt= bezt+(nu->pntsu-1); + if( BEZSELECTED(bezt) ) { + nu2= nu; + } + } + } + else break; + } + else if(nu->pntsv==1) { + bp= nu->bp; + if(nu1==0) { + if( bp->f1 & 1) nu1= nu; + else { + bp= bp+(nu->pntsu-1); + if( bp->f1 & 1 ) { + nu1= nu; + switchdirectionNurb(nu); + } + } + } + else if(nu2==0) { + if( bp->f1 & 1) { + nu2= nu; + switchdirectionNurb(nu); + } + else { + bp= bp+(nu->pntsu-1); + if( bp->f1 & 1 ) { + nu2= nu; + } + } + } + else break; + } + } + nu= nu->next; + } + + if((nu1 && nu2) && (nu1!=nu2)) { + if( nu1->type==nu2->type) { + if((nu1->type & 7)==CU_BEZIER) { + bezt = + (BezTriple*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BezTriple), "addsegmentN"); + memcpy(bezt, nu2->bezt, nu2->pntsu*sizeof(BezTriple)); + memcpy(bezt+nu2->pntsu, nu1->bezt, nu1->pntsu*sizeof(BezTriple)); + MEM_freeN(nu1->bezt); + nu1->bezt= bezt; + nu1->pntsu+= nu2->pntsu; + BLI_remlink(&editNurb, nu2); + freeNurb(nu2); + calchandlesNurb(nu1); + } + else { + bp = + (BPoint*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BPoint), "addsegmentN2"); + memcpy(bp, nu2->bp, nu2->pntsu*sizeof(BPoint) ); + memcpy(bp+nu2->pntsu, nu1->bp, nu1->pntsu*sizeof(BPoint)); + MEM_freeN(nu1->bp); + nu1->bp= bp; + + a= nu1->pntsu+nu1->orderu; + + nu1->pntsu+= nu2->pntsu; + BLI_remlink(&editNurb, nu2); + + /* en de knots aaneenrijgen */ + if((nu1->type & 7)==4) { + fp= MEM_mallocN(sizeof(float)*KNOTSU(nu1), "addsegment3"); + memcpy(fp, nu1->knotsu, sizeof(float)*a); + MEM_freeN(nu1->knotsu); + nu1->knotsu= fp; + + + offset= nu1->knotsu[a-1] +1.0; + fp= nu1->knotsu+a; + for(a=0; a<nu2->pntsu; a++, fp++) { + if(nu2->knotsu) + *fp= offset+nu2->knotsu[a+1]; + else + *fp = offset; + } + } + freeNurb(nu2); + } + } + makeDispList(G.obedit); + countall(); + allqueue(REDRAWVIEW3D, 0); + } + else error("Can't make segment"); +} + +void mouse_nurb() +{ + Nurb *nu; + BezTriple *bezt=0; + BPoint *bp=0; + short hand; + + hand= findnearestNurbvert(1, &nu, &bezt, &bp); + + if(bezt || bp) { + if((G.qual & LR_SHIFTKEY)==0) { + + setflagsNurb(0); + + if(bezt) { + + if(hand==1) { + bezt->f1|= 1; + bezt->f2|= 1; + bezt->f3|= 1; + } + else if(hand==0) bezt->f1|= 1; + else bezt->f3|= 1; + } + else { + lastselbp= bp; + bp->f1 |= 1; + } + + allqueue(REDRAWVIEW3D, 0); + } + else { + if(bezt) { + if(hand==1) { + if(bezt->f2 & 1) { + bezt->f1 &= ~1; + bezt->f2 &= ~1; + bezt->f3 &= ~1; + } + else { + bezt->f1 |= 1; + bezt->f2 |= 1; + bezt->f3 |= 1; + } + } + else if(hand==0) { + if(bezt->f1 & 1) { + bezt->f1 &= ~1; + } + else { + bezt->f1 |= 1; + } + } + else { + if(bezt->f3 & 1) { + bezt->f3 &= ~1; + } + else { + bezt->f3 |= 1; + } + } + } + else { + if(bp->f1 & 1) bp->f1 &= ~1; + else { + bp->f1 |= 1; + lastselbp= bp; + } + } + + allqueue(REDRAWVIEW3D, 0); + + } + + countall(); + } + + rightmouse_transform(); + + if(nu!=lastnu) { + lastnu= nu; + allqueue(REDRAWBUTSEDIT, 0); + } + +} + +void spinNurb(float *dvec, short mode) +/* float *dvec; */ +/* short mode; */ /* 0 is extrude, 1 is duplicate */ +{ + Nurb *nu; + float *curs, si,phi,n[3],q[4],cmat[3][3],tmat[3][3],imat[3][3]; + float cent[3],bmat[3][3], rotmat[3][3], scalemat1[3][3], scalemat2[3][3]; + float persmat[3][3], persinv[3][3]; + short a,ok; + + if(G.obedit==0 || G.obedit->type!=OB_SURF) return; + if( (G.vd->lay & G.obedit->lay)==0 ) return; + + Mat3CpyMat4(persmat, G.vd->viewmat); + Mat3Inv(persinv, persmat); + + /* imat en centrum en afmeting */ + Mat3CpyMat4(bmat, G.obedit->obmat); + Mat3Inv(imat, bmat); + + curs= give_cursor(); + VECCOPY(cent, curs); + VecSubf(cent, cent, G.obedit->obmat[3]); + Mat3MulVecfl(imat,cent); + + if(dvec) { + n[0]=n[1]= 0.0; + n[2]= 1.0; + } else { + n[0]= G.vd->viewinv[2][0]; + n[1]= G.vd->viewinv[2][1]; + n[2]= G.vd->viewinv[2][2]; + Normalise(n); + } + + phi= M_PI/8.0; + q[0]= cos(phi); + si= sin(phi); + q[1]= n[0]*si; + q[2]= n[1]*si; + q[3]= n[2]*si; + QuatToMat3(q, cmat); + Mat3MulMat3(tmat, cmat, bmat); + Mat3MulMat3(rotmat, imat, tmat); + + Mat3One(scalemat1); + scalemat1[0][0]= sqrt(2.0); + scalemat1[1][1]= sqrt(2.0); + + Mat3MulMat3(tmat,persmat,bmat); + Mat3MulMat3(cmat,scalemat1,tmat); + Mat3MulMat3(tmat,persinv,cmat); + Mat3MulMat3(scalemat1,imat,tmat); + + Mat3One(scalemat2); + scalemat2[0][0]/= sqrt(2.0); + scalemat2[1][1]/= sqrt(2.0); + + Mat3MulMat3(tmat,persmat,bmat); + Mat3MulMat3(cmat,scalemat2,tmat); + Mat3MulMat3(tmat,persinv,cmat); + Mat3MulMat3(scalemat2,imat,tmat); + + ok= 1; + + for(a=0;a<7;a++) { + if(mode==0) ok= extrudeflagNurb(1); + else adduplicateflagNurb(1); + if(ok==0) { + error("Can't spin"); + break; + } + rotateflagNurb(1,cent,rotmat); + + if(mode==0) { + if( (a & 1)==0 ) { + rotateflagNurb(1,cent,scalemat1); + weightflagNurb(1, 0.25*sqrt(2.0), 1); + } + else { + rotateflagNurb(1,cent,scalemat2); + weightflagNurb(1, 4.0/sqrt(2.0), 1); + } + } + if(dvec) { + Mat3MulVecfl(bmat,dvec); + translateflagNurb(1,dvec); + } + } + + if(ok) { + nu= editNurb.first; + while(nu) { + if(isNurbsel(nu)) { + nu->orderv= 4; + nu->flagv |= 1; + makeknots(nu, 2, nu->flagv>>1); + } + nu= nu->next; + } + } +} + +void addvert_Nurb(int mode) +{ + Nurb *nu; + BezTriple *bezt, *newbezt = NULL; + BPoint *bp, *newbp = NULL; + float *curs, mat[3][3],imat[3][3], temp[3]; + + if(G.obedit==0) return; + if( (G.vd->lay & G.obedit->lay)==0 ) return; + + if(mode=='e' && okee("Extrude")==0) return; + + Mat3CpyMat4(mat, G.obedit->obmat); + Mat3Inv(imat,mat); + + findselectedNurbvert(&nu, &bezt, &bp); + if(bezt==0 && bp==0) return; + + if((nu->type & 7)==CU_BEZIER) { + /* welk bezpoint? */ + if(bezt== nu->bezt) { /* eerste */ + bezt->f1= bezt->f2= bezt->f3= 0; + newbezt = + (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb"); + memcpy(newbezt+1, bezt, nu->pntsu*sizeof(BezTriple)); + *newbezt= *bezt; + newbezt->f1= newbezt->f2= newbezt->f3= 1; + if(bezt->h1 & 1) newbezt->h1= newbezt->h2= HD_AUTO; + else newbezt->h1= newbezt->h2= HD_VECT; + VECCOPY(temp, bezt->vec[1]); + MEM_freeN(nu->bezt); + nu->bezt= newbezt; + bezt= newbezt+1; + } + else if(bezt== (nu->bezt+nu->pntsu-1)) { /* laatste */ + bezt->f1= bezt->f2= bezt->f3= 0; + newbezt = + (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb"); + memcpy(newbezt, nu->bezt, nu->pntsu*sizeof(BezTriple)); + *(newbezt+nu->pntsu)= *bezt; + VECCOPY(temp, bezt->vec[1]); + MEM_freeN(nu->bezt); + nu->bezt= newbezt; + newbezt+= nu->pntsu; + newbezt->f1= newbezt->f2= newbezt->f3= 1; + if(newbezt->h2 & 1) newbezt->h1= newbezt->h2= HD_AUTO; + else newbezt->h1= newbezt->h2= HD_VECT; + bezt= nu->bezt+nu->pntsu-1; + } + else bezt= 0; + + if(bezt) { + nu->pntsu++; + newbezt->s[1][0]= G.vd->mx; + newbezt->s[1][1]= G.vd->my; + + if(mode=='e') { + VECCOPY(newbezt->vec[0], bezt->vec[0]); + VECCOPY(newbezt->vec[1], bezt->vec[1]); + VECCOPY(newbezt->vec[2], bezt->vec[2]); + } + else { + curs= give_cursor(); + + VECCOPY(newbezt->vec[1], curs); + VecSubf(newbezt->vec[1],newbezt->vec[1],G.obedit->obmat[3]); + Mat3MulVecfl(imat,newbezt->vec[1]); + VecSubf(temp, newbezt->vec[1],temp); + VecAddf(newbezt->vec[0], bezt->vec[0],temp); + VecAddf(newbezt->vec[2], bezt->vec[2],temp); + calchandlesNurb(nu); + } + } + } + else if(nu->pntsv==1) { + /* welk b-point? */ + if(bp== nu->bp) { /* eerste */ + bp->f1= 0; + newbp = + (BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb3"); + memcpy(newbp+1, bp, nu->pntsu*sizeof(BPoint)); + *newbp= *bp; + newbp->f1= 1; + MEM_freeN(nu->bp); + nu->bp= newbp; + } + else if(bp== (nu->bp+nu->pntsu-1)) { /* laatste */ + bp->f1= 0; + newbp = + (BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb4"); + memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint)); + *(newbp+nu->pntsu)= *bp; + MEM_freeN(nu->bp); + nu->bp= newbp; + newbp+= nu->pntsu; + newbp->f1= 1; + } + else bp= 0; + + if(bp) { + nu->pntsu++; + newbp->s[0]= G.vd->mx; + newbp->s[1]= G.vd->my; + + if(nu->resolu<3) nu->resolu++; + makeknots(nu, 1, nu->flagu>>1); + + if(mode=='e') { + VECCOPY(newbp->vec, bp->vec); + } + else { + curs= give_cursor(); + + VECCOPY(newbp->vec, curs); + VecSubf(newbp->vec, newbp->vec, G.obedit->obmat[3]); + Mat3MulVecfl(imat,newbp->vec); + newbp->vec[3]= 1.0; + } + } + } + + test2DNurb(nu); + makeDispList(G.obedit); + countall(); + allqueue(REDRAWVIEW3D, 0); + + if(mode=='e') transform('d'); + else while(get_mbut()&R_MOUSE) BIF_wait_for_statechange(); +} + +void extrude_nurb() +{ + Nurb *nu; + int ok= 0; + + if(G.obedit && G.obedit->type==OB_SURF) { + + /* first test: curve? */ + nu= editNurb.first; + while(nu) { + if(nu->pntsv==1 && isNurbsel_count(nu)==1 ) break; + nu= nu->next; + } + if(nu) { + addvert_Nurb('e'); + } + else { + + if(okee("Extrude")==0) return; + ok= extrudeflagNurb(1); /* '1'= flag */ + + if(ok) { + makeDispList(G.obedit); + countall(); + transform('d'); + } + } + } +} + + + +void makecyclicNurb() +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + float *fp; + int a, b, cyclmode=0; + + nu= editNurb.first; + while(nu) { + if( nu->pntsu>1 || nu->pntsv>1) { + if( (nu->type & 7)==0 ) { + a= nu->pntsu; + bp= nu->bp; + while(a--) { + if( bp->f1 & 1 ) { + if(nu->flagu & 1) nu->flagu--; + else nu->flagu++; + break; + } + bp++; + } + } + else if( (nu->type & 7)==CU_BEZIER ) { + a= nu->pntsu; + bezt= nu->bezt; + while(a--) { + if( BEZSELECTED(bezt) ) { + if(nu->flagu & 1) nu->flagu--; + else nu->flagu++; + break; + } + bezt++; + } + calchandlesNurb(nu); + } + else if(nu->pntsv==1 && (nu->type & 7)==CU_NURBS) { + a= nu->pntsu; + bp= nu->bp; + while(a--) { + if( bp->f1 & 1 ) { + if(nu->flagu & 1) nu->flagu--; + else { + nu->flagu++; + fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN"); + b= (nu->orderu+nu->pntsu); + memcpy(fp, nu->knotsu, sizeof(float)*b); + MEM_freeN(nu->knotsu); + nu->knotsu= fp; + + makeknots(nu, 1, 0); /* 1==u 0==uniform */ + + } + break; + } + bp++; + } + } + else if(nu->type==CU_NURBS) { + if(cyclmode==0) { + cyclmode= pupmenu("Toggle %t|cyclic U%x1|cyclic V%x2"); + if(cyclmode < 1) return; + } + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + + if( bp->f1 & 1) { + if(cyclmode==1 && nu->pntsu>1) { + if(nu->flagu & 1) nu->flagu--; + else { + nu->flagu++; + fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN"); + b= (nu->orderu+nu->pntsu); + memcpy(fp, nu->knotsu, sizeof(float)*b); + MEM_freeN(nu->knotsu); + nu->knotsu= fp; + + makeknots(nu, 1, 0); /* 1==u 0==uniform */ + } + } + if(cyclmode==2 && nu->pntsv>1) { + if(nu->flagv & 1) nu->flagv--; + else { + nu->flagv++; + fp= MEM_mallocN(sizeof(float)*KNOTSV(nu), "makecyclicN"); + b= (nu->orderv+nu->pntsv); + memcpy(fp, nu->knotsv, sizeof(float)*b); + MEM_freeN(nu->knotsv); + nu->knotsv= fp; + + makeknots(nu, 2, 0); /* 2==v 0==uniform */ + } + } + break; + } + bp++; + } + + } + } + nu= nu->next; + } + makeDispList(G.obedit); +} + +void selectconnected_nurb() +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + findnearestNurbvert(1, &nu, &bezt, &bp); + if(bezt) { + a= nu->pntsu; + bezt= nu->bezt; + while(a--) { + if(bezt->hide==0) { + if(G.qual & LR_SHIFTKEY) { + bezt->f1 &= ~1; + bezt->f2 &= ~1; + bezt->f3 &= ~1; + } + else { + bezt->f1 |= 1; + bezt->f2 |= 1; + bezt->f3 |= 1; + } + } + bezt++; + } + } + else if(bp) { + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a--) { + if(bp->hide==0) { + if(G.qual & LR_SHIFTKEY) { + bp->f1 &= ~1; + } + else { + bp->f1 |= 1; + } + } + bp++; + } + } + + countall(); + allqueue(REDRAWVIEW3D, 0); +} + +void selectrow_nurb() +{ + static BPoint *last=0; + static int direction=0; + Nurb *nu; + BPoint *bp; + int u = 0, v = 0, a, b, ok=0; + + if(editNurb.first==0) return; + if(G.obedit==0 || G.obedit->type!=OB_SURF) return; + if(lastselbp==0) return; + + /* zoek de juiste nurb en toggle met u of v */ + nu= editNurb.first; + while(nu) { + bp= nu->bp; + for(v=0; v<nu->pntsv; v++) { + for(u=0; u<nu->pntsu; u++, bp++) { + if(bp==lastselbp) { + if(bp->f1 & 1) { + ok= 1; + break; + } + } + } + if(ok) break; + } + if(ok) { + if(last==lastselbp) { + direction= 1-direction; + setflagsNurb(0); + } + last= lastselbp; + + bp= nu->bp; + for(a=0; a<nu->pntsv; a++) { + for(b=0; b<nu->pntsu; b++, bp++) { + if(direction) { + if(a==v) if(bp->hide==0) bp->f1 |= 1; + } + else { + if(b==u) if(bp->hide==0) bp->f1 |= 1; + } + } + } + countall(); + allqueue(REDRAWVIEW3D, 0); + return; + } + nu= nu->next; + } +} + +void adduplicate_nurb() +{ + + if( (G.vd->lay & G.obedit->lay)==0 ) return; + + adduplicateflagNurb(1); + + countall(); + transform('d'); +} + +void delNurb() +{ + Nurb *nu, *next, *nu1; + BezTriple *bezt, *bezt1, *bezt2; + BPoint *bp, *bp1, *bp2; + int a; + short event, cut = 0; + + if(G.obedit==0 ) return; + if( (G.vd->lay & G.obedit->lay)==0 ) return; + + if(G.obedit->type==OB_SURF) event= pupmenu("ERASE %t|Selected%x0|All%x2"); + else event= pupmenu("ERASE %t|Selected%x0|Segment%x1|All%x2"); + + if(event== -1) return; + + if(G.obedit->type==OB_SURF) { + if(event==0) deleteflagNurb(1); + else freeNurblist(&editNurb); + + countall(); + makeDispList(G.obedit); + allqueue(REDRAWVIEW3D, 0); + return; + } + + if(event==0) { + /* eerste doorloop, kunnen hele stukken weg? */ + nu= editNurb.first; + while(nu) { + next= nu->next; + if( (nu->type & 7)==CU_BEZIER ) { + bezt= nu->bezt; + a= nu->pntsu; + if(a) { + while(a) { + if( BEZSELECTED(bezt) ); + else break; + a--; + bezt++; + } + if(a==0) { + BLI_remlink(&editNurb, nu); + freeNurb(nu); + } + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + if(a) { + while(a) { + if(bp->f1 & 1 ); + else break; + a--; + bp++; + } + if(a==0) { + BLI_remlink(&editNurb, nu); + freeNurb(nu); + } + } + } + nu= next; + } + /* tweede doorloop, kleine stukken weg: alleen curves */ + nu= editNurb.first; + while(nu) { + next= nu->next; + event= 0; + if( (nu->type & 7)==CU_BEZIER ) { + bezt= nu->bezt; + for(a=0;a<nu->pntsu;a++) { + if( BEZSELECTED(bezt) ) { + memcpy(bezt, bezt+1, (nu->pntsu-a-1)*sizeof(BezTriple)); + nu->pntsu--; + a--; + event= 1; + } + else bezt++; + } + if(event) { + bezt1 = + (BezTriple*)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "delNurb"); + memcpy(bezt1, nu->bezt, (nu->pntsu)*sizeof(BezTriple) ); + MEM_freeN(nu->bezt); + nu->bezt= bezt1; + calchandlesNurb(nu); + } + } + else if(nu->pntsv==1) { + bp= nu->bp; + + for(a=0;a<nu->pntsu;a++) { + if( bp->f1 & 1 ) { + memcpy(bp, bp+1, (nu->pntsu-a-1)*sizeof(BPoint)); + nu->pntsu--; + a--; + event= 1; + } + else { + bp++; + } + } + if(event) { + bp1 = (BPoint*)MEM_mallocN(nu->pntsu * sizeof(BPoint), "delNurb2"); + memcpy(bp1, nu->bp, (nu->pntsu)*sizeof(BPoint) ); + MEM_freeN(nu->bp); + nu->bp= bp1; + } + makeknots(nu, 1, nu->flagu>>1); + } + nu= next; + } + } + else if(event==1) { /* erase segment */ + /* vind de twee geselecteerde punten */ + bezt1= bezt2= 0; + bp1= bp2= 0; + nu= editNurb.first; + nu1= 0; + while(nu) { + next= nu->next; + if( (nu->type & 7)==CU_BEZIER ) { + bezt= nu->bezt; + for(a=0; a<nu->pntsu-1; a++) { + if( BEZSELECTED(bezt) ) { + bezt1= bezt; + bezt2= bezt+1; + if( (bezt2->f1 & 1) || (bezt2->f2 & 1) || (bezt2->f3 & 1) ) ; + else { /* misschien niet cyclic maken */ + if(a==0 && (nu->flagu & 1) ) { + bezt2= bezt+(nu->pntsu-1); + if( (bezt2->f1 & 1) || (bezt2->f2 & 1) || (bezt2->f3 & 1) ) { + nu->flagu--; + makeDispList(G.obedit); + allqueue(REDRAWVIEW3D, 0); + } + } + return; + } + cut= a; + nu1= nu; + break; + } + bezt++; + } + } + else if(nu->pntsv==1) { + bp= nu->bp; + for(a=0; a<nu->pntsu-1; a++) { + if( bp->f1 & 1 ) { + bp1= bp; + bp2= bp+1; + if( bp2->f1 & 1 ) ; + else { /* misschien niet cyclic maken */ + if(a==0 && (nu->flagu & 1) ) { + bp2= bp+(nu->pntsu-1); + if( bp2->f1 & 1 ) { + nu->flagu--; + makeDispList(G.obedit); + allqueue(REDRAWVIEW3D, 0); + } + } + return; + } + cut= a; + nu1= nu; + break; + } + bp++; + } + } + if(nu1) break; + + nu= nu->next; + } + if(nu1) { + if(bezt1) { + if(nu1->pntsu==2) { /* helemaal weg */ + BLI_remlink(&editNurb, nu); + freeNurb(nu); + } + else if(nu1->flagu & 1) { /* cyclic */ + bezt = + (BezTriple*)MEM_mallocN((cut+1) * sizeof(BezTriple), "delNurb1"); + memcpy(bezt, nu1->bezt,(cut+1)*sizeof(BezTriple)); + a= nu1->pntsu-cut-1; + memcpy(nu1->bezt, bezt2, a*sizeof(BezTriple)); + memcpy(nu1->bezt+a, bezt, (cut+1)*sizeof(BezTriple)); + nu1->flagu--; + MEM_freeN(bezt); + calchandlesNurb(nu); + } + else { /* nieuwe curve erbij */ + +/* hier zit een fout in... maar waar? (a kan nul worden) */ + + nu = + (Nurb*)MEM_mallocN(sizeof(Nurb), "delNurb2"); + memcpy(nu, nu1, sizeof(Nurb)); + BLI_addtail(&editNurb, nu); + nu->bezt = + (BezTriple*)MEM_mallocN((cut+1) * sizeof(BezTriple), "delNurb3"); + memcpy(nu->bezt, nu1->bezt,(cut+1)*sizeof(BezTriple)); + a= nu1->pntsu-cut-1; + + bezt = + (BezTriple*)MEM_mallocN(a * sizeof(BezTriple), "delNurb4"); + memcpy(bezt, nu1->bezt+cut+1,a*sizeof(BezTriple)); + MEM_freeN(nu1->bezt); + nu1->bezt= bezt; + nu1->pntsu= a; + nu->pntsu= cut+1; + + + calchandlesNurb(nu); + calchandlesNurb(nu1); + } + } + else if(bp1) { + if(nu1->pntsu==2) { /* helemaal weg */ + BLI_remlink(&editNurb, nu); + freeNurb(nu); + } + else if(nu1->flagu & 1) { /* cyclic */ + bp = + (BPoint*)MEM_mallocN((cut+1) * sizeof(BPoint), "delNurb5"); + memcpy(bp, nu1->bp,(cut+1)*sizeof(BPoint)); + a= nu1->pntsu-cut-1; + memcpy(nu1->bp, bp2, a*sizeof(BPoint)); + memcpy(nu1->bp+a, bp, (cut+1)*sizeof(BPoint)); + nu1->flagu--; + MEM_freeN(bp); + } + else { /* nieuwe curve erbij */ + nu = (Nurb*)MEM_mallocN(sizeof(Nurb), "delNurb6"); + memcpy(nu, nu1, sizeof(Nurb)); + BLI_addtail(&editNurb, nu); + nu->bp = + (BPoint*)MEM_mallocN((cut+1) * sizeof(BPoint), "delNurb7"); + memcpy(nu->bp, nu1->bp,(cut+1)*sizeof(BPoint)); + a= nu1->pntsu-cut-1; + bp = + (BPoint*)MEM_mallocN(a * sizeof(BPoint), "delNurb8"); + memcpy(bp, nu1->bp+cut+1,a*sizeof(BPoint)); + MEM_freeN(nu1->bp); + nu1->bp= bp; + nu1->pntsu= a; + nu->pntsu= cut+1; + } + } + } + } + else if(event==2) { + freeNurblist(&editNurb); + } + + countall(); + makeDispList(G.obedit); + allqueue(REDRAWVIEW3D, 0); +} + + +void join_curve(int type) +{ + Base *base, *nextb; + Object *ob; + Curve *cu; + Nurb *nu, *newnu; + BezTriple *bezt; + BPoint *bp; + ListBase tempbase; + float imat[4][4], cmat[4][4]; + int a; + + if(G.obedit) return; + + ob= OBACT; + if(ob->type!=type) return; + if(ob->lay & G.vd->lay); else return; + tempbase.first= tempbase.last= 0; + + if(type==OB_SURF) { + if(okee("Join selected Nurbs")==0) return; + } + else if(okee("Join selected Curves")==0) return; + + /* alle geselecteerde curves invers transformen in obact */ + Mat4Invert(imat, ob->obmat); + + base= FIRSTBASE; + while(base) { + nextb= base->next; + if TESTBASE(base) { + if(base->object->type==type) { + if(base->object != ob) { + + cu= base->object->data; + + if(cu->nurb.first) { + /* let op: matmul omkeren is ECHT fout */ + Mat4MulMat4(cmat, base->object->obmat, imat); + + nu= cu->nurb.first; + while(nu) { + newnu= duplicateNurb(nu); + BLI_addtail(&tempbase, newnu); + + if( (bezt= newnu->bezt) ) { + a= newnu->pntsu; + while(a--) { + Mat4MulVecfl(cmat, bezt->vec[0]); + Mat4MulVecfl(cmat, bezt->vec[1]); + Mat4MulVecfl(cmat, bezt->vec[2]); + bezt++; + } + } + if( (bp= newnu->bp) ) { + a= newnu->pntsu*nu->pntsv; + while(a--) { + Mat4MulVecfl(cmat, bp->vec); + bp++; + } + } + nu= nu->next; + } + } + + free_and_unlink_base(base); + } + } + } + base= nextb; + } + + cu= ob->data; + addlisttolist(&cu->nurb, &tempbase); + + enter_editmode(); + exit_editmode(1); + + allqueue(REDRAWVIEW3D, 0); +} + + + +Nurb *addNurbprim(int type, int stype, int newname) +/* type: &8= 2D; 0=poly,1 bez, 4 nurb + * stype: 0: 2/4 punts curve + * 1: 8 punts cirkel + * 2: 4x4 patch Nurb + * 3: tube 4:sphere 5:donut + * 6: 5 punts, 5e order rechte lijn (pad) alleen nurbspline! + */ +{ + static int xzproj= 0; + Nurb *nu = NULL; + BezTriple *bezt; + BPoint *bp; + float *curs, cent[3],vec[3],imat[3][3],mat[3][3]; + float fac,cmat[3][3]; + int a, b; + + /* imat en centrum en afmeting */ + if(G.obedit) { + + Mat3CpyMat4(mat, G.obedit->obmat); + curs= give_cursor(); + VECCOPY(cent, curs); + cent[0]-= G.obedit->obmat[3][0]; + cent[1]-= G.obedit->obmat[3][1]; + cent[2]-= G.obedit->obmat[3][2]; + + Mat3CpyMat4(imat, G.vd->viewmat); + Mat3MulVecfl(imat, cent); + Mat3MulMat3(cmat, imat, mat); + Mat3Inv(imat, cmat); + setflagsNurb(0); + } + else { + Mat3One(imat); + cent[0]= cent[1]= cent[2]= 0.0; + } + + if ELEM5(stype, 0, 1, 2, 4, 6) { + nu = (Nurb*)MEM_callocN(sizeof(Nurb), "addNurbprim"); + nu->type= type; + nu->resolu= 12; + nu->resolv= 12; + /* if(G.obedit && (G.mainb==5 || G.mainb==9)) nu->col= 0; */ + } + + switch(stype) { + case 0: /* curve */ + if(newname) { + rename_id((ID *)G.obedit, "Curve"); + rename_id((ID *)G.obedit->data, "Curve"); + } + if((type & 7)==CU_BEZIER) { + nu->pntsu= 2; + nu->bezt = + (BezTriple*)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1"); + bezt= nu->bezt; + bezt->h1= bezt->h2= HD_ALIGN; + bezt->f1= bezt->f2= bezt->f3= 1; + + for(a=0;a<3;a++) { + VECCOPY(bezt->vec[a], cent); + } + bezt->vec[1][0]+= -G.vd->grid; + bezt->vec[0][0]+= -1.5*G.vd->grid; + bezt->vec[0][1]+= -0.5*G.vd->grid; + bezt->vec[2][0]+= -0.5*G.vd->grid; + bezt->vec[2][1]+= 0.5*G.vd->grid; + for(a=0;a<3;a++) Mat3MulVecfl(imat, bezt->vec[a]); + + bezt++; + bezt->h1= bezt->h2= HD_ALIGN; + bezt->f1= bezt->f2= bezt->f3= 1; + + for(a=0;a<3;a++) { + VECCOPY(bezt->vec[a], cent); + } + bezt->vec[1][0]+= G.vd->grid; + for(a=0;a<3;a++) Mat3MulVecfl(imat, bezt->vec[a]); + + calchandlesNurb(nu); + } + else { + nu->pntsu= 4; + nu->pntsv= 1; + nu->orderu= 4; + nu->bp= callocstructN(BPoint, 4, "addNurbprim3"); + + bp= nu->bp; + for(a=0;a<4;a++, bp++) { + VECCOPY(bp->vec, cent); + bp->vec[3]= 1.0; + bp->f1= 1; + } + + bp= nu->bp; + bp->vec[0]+= -1.5*G.vd->grid; + bp++; + bp->vec[0]+= -G.vd->grid; + bp->vec[1]+= G.vd->grid; + bp++; + bp->vec[0]+= G.vd->grid; + bp->vec[1]+= G.vd->grid; + bp++; + bp->vec[0]+= 1.5*G.vd->grid; + + bp= nu->bp; + for(a=0;a<4;a++, bp++) Mat3MulVecfl(imat,bp->vec); + + if((type & 7)==4) { + nu->knotsu= 0; /* makeknots alloceert */ + makeknots(nu, 1, nu->flagu>>1); + } + + } + break; + case 6: /* 5 punts pad */ + nu->pntsu= 5; + nu->pntsv= 1; + nu->orderu= 5; + nu->flagu= 2; /* endpoint */ + nu->resolu= 32; + nu->bp= callocstructN(BPoint, 5, "addNurbprim3"); + + bp= nu->bp; + for(a=0;a<5;a++, bp++) { + VECCOPY(bp->vec, cent); + bp->vec[3]= 1.0; + bp->f1= 1; + } + + bp= nu->bp; + bp->vec[0]+= -2.0*G.vd->grid; + bp++; + bp->vec[0]+= -G.vd->grid; + bp++; bp++; + bp->vec[0]+= G.vd->grid; + bp++; + bp->vec[0]+= 2.0*G.vd->grid; + + bp= nu->bp; + for(a=0;a<5;a++, bp++) Mat3MulVecfl(imat,bp->vec); + + if((type & 7)==4) { + nu->knotsu= 0; /* makeknots alloceert */ + makeknots(nu, 1, nu->flagu>>1); + } + + break; + case 1: /* cirkel */ + if(newname) { + rename_id((ID *)G.obedit, "CurveCircle"); + rename_id((ID *)G.obedit->data, "CurveCircle"); + } + if((type & 7)==CU_BEZIER) { + nu->pntsu= 4; + nu->bezt= callocstructN(BezTriple, 4, "addNurbprim1"); + nu->flagu= 1; + bezt= nu->bezt; + + for(a=0;a<3;a++) { + VECCOPY(bezt->vec[a], cent); + } + bezt->h1= bezt->h2= HD_AUTO; + bezt->f1= bezt->f2= bezt->f3= 1; + bezt->vec[1][0]+= -G.vd->grid; + for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]); + + bezt++; + for(a=0;a<3;a++) { + VECCOPY(bezt->vec[a], cent); + } + bezt->h1= bezt->h2= HD_AUTO; + bezt->f1= bezt->f2= bezt->f3= 1; + bezt->vec[1][1]+= G.vd->grid; + for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]); + + bezt++; + for(a=0;a<3;a++) { + VECCOPY(bezt->vec[a], cent); + } + bezt->h1= bezt->h2= HD_AUTO; + bezt->f1= bezt->f2= bezt->f3= 1; + bezt->vec[1][0]+= G.vd->grid; + for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]); + + bezt++; + for(a=0;a<3;a++) { + VECCOPY(bezt->vec[a], cent); + } + bezt->h1= bezt->h2= HD_AUTO; + bezt->f1= bezt->f2= bezt->f3= 1; + bezt->vec[1][1]+= -G.vd->grid; + for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]); + + calchandlesNurb(nu); + } + else if( (type & 7)==CU_NURBS ) { /* nurb */ + nu->pntsu= 8; + nu->pntsv= 1; + nu->orderu= 4; + nu->bp= callocstructN(BPoint, 8, "addNurbprim6"); + nu->flagu= 1; + bp= nu->bp; + + for(a=0; a<8; a++) { + bp->f1= 1; + VECCOPY(bp->vec, cent); + + if(xzproj==0) { + bp->vec[0]+= nurbcircle[a][0]*G.vd->grid; + bp->vec[1]+= nurbcircle[a][1]*G.vd->grid; + } + else { + bp->vec[0]+= 0.25*nurbcircle[a][0]*G.vd->grid-.75*G.vd->grid; + bp->vec[2]+= 0.25*nurbcircle[a][1]*G.vd->grid; + } + if(a & 1) bp->vec[3]= 0.25*sqrt(2.0); + else bp->vec[3]= 1.0; + Mat3MulVecfl(imat,bp->vec); + bp++; + } + + makeknots(nu, 1, nu->flagu>>1); + } + break; + case 2: /* 4x4 patch */ + if( (type & 7)==CU_NURBS ) { /* nurb */ + if(newname) { + rename_id((ID *)G.obedit, "Surf"); + rename_id((ID *)G.obedit->data, "Surf"); + } + + nu->pntsu= 4; + nu->pntsv= 4; + nu->orderu= 4; + nu->orderv= 4; + nu->flag= ME_SMOOTH; + nu->bp= callocstructN(BPoint, 4*4, "addNurbprim6"); + nu->flagu= 0; + nu->flagv= 0; + bp= nu->bp; + + for(a=0; a<4; a++) { + for(b=0; b<4; b++) { + VECCOPY(bp->vec, cent); + bp->f1= 1; + fac= (float)a -1.5; + bp->vec[0]+= fac*G.vd->grid; + fac= (float)b -1.5; + bp->vec[1]+= fac*G.vd->grid; + if(a==1 || a==2) if(b==1 || b==2) { + bp->vec[2]+= G.vd->grid; + } + Mat3MulVecfl(imat,bp->vec); + bp->vec[3]= 1.0; + bp++; + } + } + + makeknots(nu, 1, nu->flagu>>1); + makeknots(nu, 2, nu->flagv>>1); + } + break; + case 3: /* tube */ + if( (type & 7)==CU_NURBS ) { + if(newname) { + rename_id((ID *)G.obedit, "SurfTube"); + rename_id((ID *)G.obedit->data, "SurfTube"); + } + + nu= addNurbprim(4, 1, 0); /* cirkel */ + nu->resolu= 32; + nu->flag= ME_SMOOTH; + BLI_addtail(&editNurb, nu); /* tijdelijk voor extrude en translate */ + vec[0]=vec[1]= 0.0; + vec[2]= -G.vd->grid; + Mat3MulVecfl(imat, vec); + translateflagNurb(1, vec); + extrudeflagNurb(1); + vec[0]= -2*vec[0]; + vec[1]= -2*vec[1]; + vec[2]= -2*vec[2]; + translateflagNurb(1, vec); + + BLI_remlink(&editNurb, nu); + + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a-- >0) { + bp->f1 |= 1; + bp++; + } + } + break; + case 4: /* sphere */ + if( (type & 7)==CU_NURBS ) { + if(newname) { + rename_id((ID *)G.obedit, "SurfSphere"); + rename_id((ID *)G.obedit->data, "SurfSphere"); + } + + nu->pntsu= 5; + nu->pntsv= 1; + nu->orderu= 3; + nu->resolu= 24; + nu->resolv= 32; + nu->flag= ME_SMOOTH; + nu->bp= callocstructN(BPoint, 5, "addNurbprim6"); + nu->flagu= 0; + bp= nu->bp; + + for(a=0; a<5; a++) { + bp->f1= 1; + VECCOPY(bp->vec, cent); + bp->vec[0]+= nurbcircle[a][0]*G.vd->grid; + bp->vec[2]+= nurbcircle[a][1]*G.vd->grid; + if(a & 1) bp->vec[3]= 0.5*sqrt(2.0); + else bp->vec[3]= 1.0; + Mat3MulVecfl(imat,bp->vec); + bp++; + } + nu->flagu= 4; + makeknots(nu, 1, nu->flagu>>1); + + BLI_addtail(&editNurb, nu); /* tijdelijk voor spin */ + spinNurb(0, 0); + + makeknots(nu, 2, nu->flagv>>1); + + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a-- >0) { + bp->f1 |= 1; + bp++; + } + BLI_remlink(&editNurb, nu); + } + break; + case 5: /* donut */ + if( (type & 7)==CU_NURBS ) { + if(newname) { + rename_id((ID *)G.obedit, "SurfDonut"); + rename_id((ID *)G.obedit->data, "SurfDonut"); + } + + xzproj= 1; + nu= addNurbprim(4, 1, 0); /* cirkel */ + xzproj= 0; + nu->resolu= 24; + nu->resolv= 32; + nu->flag= ME_SMOOTH; + BLI_addtail(&editNurb, nu); /* tijdelijk voor extrude en translate */ + spinNurb(0, 0); + + BLI_remlink(&editNurb, nu); + + a= nu->pntsu*nu->pntsv; + bp= nu->bp; + while(a-- >0) { + bp->f1 |= 1; + bp++; + } + + } + break; + } + + /* altijd doen: */ + nu->flag= ME_SMOOTH; + + test2DNurb(nu); + + return nu; +} + +void default_curve_ipo(Curve *cu) +{ + IpoCurve *icu; + BezTriple *bezt; + + if(cu->ipo) return; + + cu->ipo= add_ipo("CurveIpo", ID_CU); + + icu= MEM_callocN(sizeof(IpoCurve), "ipocurve"); + + icu->blocktype= ID_CU; + icu->adrcode= CU_SPEED; + icu->flag= IPO_VISIBLE+IPO_SELECT; + set_icu_vars(icu); + + BLI_addtail( &(cu->ipo->curve), icu); + + icu->bezt= bezt= MEM_callocN(2*sizeof(BezTriple), "defaultipo"); + icu->totvert= 2; + + bezt->hide= IPO_BEZ; + bezt->f1=bezt->f2= bezt->f3= SELECT; + bezt->h1= bezt->h2= HD_AUTO; + bezt++; + bezt->vec[1][0]= 100.0; + bezt->vec[1][1]= 1.0; + bezt->hide= IPO_BEZ; + bezt->f1=bezt->f2= bezt->f3= SELECT; + bezt->h1= bezt->h2= HD_AUTO; + + calchandles_ipocurve(icu); +} + +void add_primitiveCurve(int stype) +{ + Nurb *nu; + Curve *cu; + int type, newname= 0; + + if(G.scene->id.lib) return; + + /* this function also comes from an info window */ + if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return; + if(G.vd==0) return; + + if(stype>=10 && stype<20) type= CU_2D+1; + else if(stype>=20 && stype<30) type= CU_2D+2; + else if(stype>=30 && stype<40) type= CU_2D+3; + else if(stype>=40 && stype<50) { + if(stype==46) type= 4; + else type= CU_2D+4; + } + else type= CU_2D; + + check_editmode(OB_CURVE); + + /* als geen obedit: nieuw object en in editmode gaan */ + if(G.obedit==0) { + add_object(OB_CURVE); + base_init_from_view3d(BASACT, G.vd); + G.obedit= BASACT->object; + + where_is_object(G.obedit); + + make_editNurb(); + setcursor_space(SPACE_VIEW3D, CURSOR_EDIT); + newname= 1; + + cu= G.obedit->data; + if(stype==46) { + cu->flag |= (CU_3D+CU_PATH); + + default_curve_ipo(cu); + } + } + else cu= G.obedit->data; + + if(cu->flag & CU_3D) type &= ~CU_2D; + + stype= (stype % 10); + + nu= addNurbprim(type, stype, newname); /* 2D */ + + BLI_addtail(&editNurb, nu); + makeDispList(G.obedit); + + allqueue(REDRAWBUTSEDIT, 0); + + countall(); + allqueue(REDRAWVIEW3D, 0); +} + +void add_primitiveNurb(int type) +{ + Nurb *nu; + int newname= 0; + + if(G.scene->id.lib) return; + if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return; + + check_editmode(OB_SURF); + + /* als geen obedit: nieuw object en in editmode gaan */ + if(G.obedit==0) { + add_object(OB_SURF); + base_init_from_view3d(BASACT, G.vd); + G.obedit= BASACT->object; + + where_is_object(G.obedit); + + make_editNurb(); + setcursor_space(SPACE_VIEW3D, CURSOR_EDIT); + newname= 1; + } + + nu= addNurbprim(4, type, newname); + BLI_addtail(&editNurb,nu); + makeDispList(G.obedit); + + allqueue(REDRAWBUTSEDIT, 0); + + countall(); + allqueue(REDRAWVIEW3D, 0); +} + + + +void clear_tilt() +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + if(okee("Clear tilt")==0) return; + + nu= editNurb.first; + while(nu) { + if( nu->bezt ) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(BEZSELECTED(bezt)) bezt->alfa= 0.0; + bezt++; + } + } + else if(nu->bp) { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if(bp->f1 & 1) bp->alfa= 0.0; + bp++; + } + } + nu= nu->next; + } + + makeBevelList(G.obedit); + allqueue(REDRAWVIEW3D, 0); +} + +void clever_numbuts_curve() +{ + BPoint *bp; + BezTriple *bezt; + float old[3], delta[3]; + int a; + + if(lastnu==0) return; + if(lastnu->bp) { + bp= lastnu->bp; + a= lastnu->pntsu*lastnu->pntsv; + while(a--) { + if(bp->f1 & 1) break; + bp++; + } + if(bp==0) return; + + add_numbut(0, NUM|FLO, "LocX:", -G.vd->far, G.vd->far, bp->vec, 0); + add_numbut(1, NUM|FLO, "LocY:", -G.vd->far, G.vd->far, bp->vec+1, 0); + add_numbut(2, NUM|FLO, "LocZ:", -G.vd->far, G.vd->far, bp->vec+2, 0); + add_numbut(3, NUM|FLO, " W:", 0.0, 100.0, bp->vec+3, 0); + + do_clever_numbuts("Active BPoint", 4, REDRAW); + makeDispList(G.obedit); + } + else if(lastnu->bezt) { + bezt= lastnu->bezt; + a= lastnu->pntsu; + while(a--) { + if(BEZSELECTED(bezt)) break; + bezt++; + } + if(bezt==0) return; + + if(bezt->f2 & 1) { + add_numbut(0, NUM|FLO, "LocX:", -G.vd->far, G.vd->far, bezt->vec[1], 0); + add_numbut(1, NUM|FLO, "LocY:", -G.vd->far, G.vd->far, bezt->vec[1]+1, 0); + add_numbut(2, NUM|FLO, "LocZ:", -G.vd->far, G.vd->far, bezt->vec[1]+2, 0); + VECCOPY(old, bezt->vec[1]); + do_clever_numbuts("Active BezierPoint", 3, REDRAW); + + VecSubf(delta, bezt->vec[1], old); + VecAddf(bezt->vec[0], bezt->vec[0], delta); + VecAddf(bezt->vec[2], bezt->vec[2], delta); + makeDispList(G.obedit); + } + else if(bezt->f1 & 1) { + add_numbut(0, NUM|FLO, "LocX:", -G.vd->far, G.vd->far, bezt->vec[0], 0); + add_numbut(1, NUM|FLO, "LocY:", -G.vd->far, G.vd->far, bezt->vec[0]+1, 0); + add_numbut(2, NUM|FLO, "LocZ:", -G.vd->far, G.vd->far, bezt->vec[0]+2, 0); + + do_clever_numbuts("Active HandlePoint", 3, REDRAW); + } + else if(bezt->f3 & 1) { + add_numbut(0, NUM|FLO, "LocX:", -G.vd->far, G.vd->far, bezt->vec[0], 0); + add_numbut(1, NUM|FLO, "LocY:", -G.vd->far, G.vd->far, bezt->vec[2]+1, 0); + add_numbut(2, NUM|FLO, "LocZ:", -G.vd->far, G.vd->far, bezt->vec[2]+2, 0); + + do_clever_numbuts("Active HandlePoint", 3, REDRAW); + } + } + +} + +int bezt_compare (const void *e1, const void *e2) +{ + BezTriple *b1 = *((BezTriple**)e1); + BezTriple *b2 = *((BezTriple**)e2); + + /* Check numerical values */ + float val = b1->vec[1][0] - b2->vec[1][0]; + + if (val<0) + return -1; + + if (val>0) + return 1; + + /* Check selected flags : Ensures that selected keys will be listed first */ + + if ((b1->f2 & 1) && !(b2->f2 & 1)) + return -1; + if (!(b1->f2 & 1) && (b2->f2 & 1)) + return 1; + + return 0; +} |