1519
1278
void remake_editMesh(void)
1521
undo_push_mesh("Undo all changes");
1522
1280
make_editMesh();
1523
1281
allqueue(REDRAWVIEW3D, 0);
1524
1282
makeDispList(G.obedit);
1527
/* ********************* TOOLS ********************* */
1531
void make_sticky(void)
1538
float ho[4], mat[4][4];
1541
if(G.scene->camera==0) return;
1544
error("Unable to perform function in EditMode");
1549
if TESTBASELIB(base) {
1550
if(base->object->type==OB_MESH) {
1555
if(me->msticky) MEM_freeN(me->msticky);
1556
me->msticky= MEM_mallocN(me->totvert*sizeof(MSticky), "sticky");
1558
/* like convert to render data */
1560
R.r.xsch= (R.r.size*R.r.xsch)/100;
1561
R.r.ysch= (R.r.size*R.r.ysch)/100;
1566
R.ycor= ( (float)R.r.yasp)/( (float)R.r.xasp);
1572
R.xend= R.xstart+R.rectx-1;
1573
R.yend= R.ystart+R.recty-1;
1575
where_is_object(G.scene->camera);
1576
Mat4CpyMat4(R.viewinv, G.scene->camera->obmat);
1577
Mat4Ortho(R.viewinv);
1578
Mat4Invert(R.viewmat, R.viewinv);
1580
RE_setwindowclip(1, -1);
1582
where_is_object(ob);
1583
Mat4MulMat4(mat, ob->obmat, R.viewmat);
1586
for(a=0; a<me->totvert; a++, ms++, mvert++) {
1587
VECCOPY(ho, mvert->co);
1588
Mat4MulVecfl(mat, ho);
1589
RE_projectverto(ho, ho);
1590
ms->co[0]= ho[0]/ho[3];
1591
ms->co[1]= ho[1]/ho[3];
1597
allqueue(REDRAWBUTSEDIT, 0);
1600
void fasterdraw(void)
1607
if(G.obedit) return;
1610
me= G.main->mesh.first;
1612
me->flag &= ~ME_ISDONE;
1618
if( TESTBASELIB(base) && (base->object->type==OB_MESH)) {
1619
me= base->object->data;
1620
if(me->id.lib==0 && (me->flag & ME_ISDONE)==0) {
1621
me->flag |= ME_ISDONE;
1624
for(a=0; a<me->totface; a++) {
1625
if( (mface->edcode & ME_V1V2) && ( (toggle++) & 1) ) {
1626
mface->edcode-= ME_V1V2;
1628
if( (mface->edcode & ME_V2V3) && ( (toggle++) & 1)) {
1629
mface->edcode-= ME_V2V3;
1631
if( (mface->edcode & ME_V3V1) && ( (toggle++) & 1)) {
1632
mface->edcode-= ME_V3V1;
1634
if( (mface->edcode & ME_V4V1) && ( (toggle++) & 1)) {
1635
mface->edcode-= ME_V4V1;
1637
if( (mface->edcode & ME_V3V4) && ( (toggle++) & 1)) {
1638
mface->edcode-= ME_V3V4;
1647
/* important?: reset flags again */
1648
me= G.main->mesh.first;
1650
me->flag &= ~ME_ISDONE;
1654
allqueue(REDRAWVIEW3D, 0);
1657
void slowerdraw(void) /* reset fasterdraw */
1664
if(G.obedit) return;
1668
if( TESTBASELIB(base) && (base->object->type==OB_MESH)) {
1669
me= base->object->data;
1674
for(a=0; a<me->totface; a++) {
1676
mface->edcode |= ME_V1V2|ME_V2V3;
1684
allqueue(REDRAWVIEW3D, 0);
1688
void convert_to_triface(int all)
1690
EditMesh *em = G.editMesh;
1691
EditVlak *evl, *evln, *next;
1693
undo_push_mesh("Convert to triangles");
1695
evl= em->faces.first;
1699
if(all || vlakselectedAND(evl, 1) ) {
1701
evln= addvlaklist(evl->v1, evl->v2, evl->v3, 0, evl);
1702
evln= addvlaklist(evl->v1, evl->v3, evl->v4, 0, evl);
1704
evln->tf.uv[1][0]= evln->tf.uv[2][0];
1705
evln->tf.uv[1][1]= evln->tf.uv[2][1];
1706
evln->tf.uv[2][0]= evln->tf.uv[3][0];
1707
evln->tf.uv[2][1]= evln->tf.uv[3][1];
1709
evln->tf.col[1]= evln->tf.col[2];
1710
evln->tf.col[2]= evln->tf.col[3];
1712
BLI_remlink(&em->faces, evl);
1722
void deselectall_mesh(void) /* toggle */
1724
EditMesh *em = G.editMesh;
1728
if(G.obedit->lay & G.vd->lay) {
1730
eve= em->verts.first;
1739
if (a) undo_push_mesh("Deselect all");
1740
else undo_push_mesh("Select all");
1742
eve= em->verts.first;
1752
allqueue(REDRAWVIEW3D, 0);
1756
void righthandfaces(int select) /* makes faces righthand turning */
1758
EditMesh *em = G.editMesh;
1759
EditEdge *eed, *ed1, *ed2, *ed3, *ed4;
1760
EditVlak *evl, *startvl;
1761
float maxx, nor[3], cent[3];
1762
int totsel, found, foundone, direct, turn;
1764
/* based at a select-connected to witness loose objects */
1766
/* count per edge the amount of faces */
1768
/* find the ultimate left, front, upper face */
1770
/* put normal to the outside, and set the first direction flags in edges */
1772
/* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */
1773
/* this is in fact the 'select connected' */
1775
/* in case (selected) faces were not done: start over with 'find the ultimate ...' */
1779
eed= em->edges.first;
1786
/* count faces and edges */
1788
evl= em->faces.first;
1790
if(select==0 || vlakselectedAND(evl, 1) ) {
1796
if(evl->v4) evl->e4->f1++;
1804
/* from the outside to the inside */
1806
evl= em->faces.first;
1812
CalcCent3f(cent, evl->v1->co, evl->v2->co, evl->v3->co);
1813
cent[0]= fabs(cent[0])+fabs(cent[1])+fabs(cent[2]);
1823
/* set first face correct: calc normal */
1824
CalcNormFloat(startvl->v1->co, startvl->v2->co, startvl->v3->co, nor);
1825
CalcCent3f(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
1827
/* first normal is oriented this way or the other */
1830
if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0) flipvlak(startvl);
1833
if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipvlak(startvl);
1836
else if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipvlak(startvl);
1840
if(eed->v1==startvl->v1) eed->f= 1;
1844
if(eed->v1==startvl->v2) eed->f= 1;
1848
if(eed->v1==startvl->v3) eed->f= 1;
1853
if(eed->v1==startvl->v4) eed->f= 1;
1865
if(direct) evl= em->faces.first;
1866
else evl= em->faces.last;
1878
if(ed1->v1==evl->v1 && ed1->f==1) turn= 1;
1879
if(ed1->v2==evl->v1 && ed1->f==2) turn= 1;
1883
if(ed2->v1==evl->v2 && ed2->f==1) turn= 1;
1884
if(ed2->v2==evl->v2 && ed2->f==2) turn= 1;
1888
if(ed3->v1==evl->v3 && ed3->f==1) turn= 1;
1889
if(ed3->v2==evl->v3 && ed3->f==2) turn= 1;
1892
else if(ed4 && ed4->f) {
1893
if(ed4->v1==evl->v4 && ed4->f==1) turn= 1;
1894
if(ed4->v2==evl->v4 && ed4->f==2) turn= 1;
1904
if(ed1->v1==evl->v1) ed1->f= 2;
1906
if(ed2->v1==evl->v2) ed2->f= 2;
1908
if(ed3->v1==evl->v3) ed3->f= 2;
1911
if(ed4->v1==evl->v4) ed4->f= 2;
1919
if(ed1->v1== evl->v1) ed1->f= 1;
1921
if(ed2->v1==evl->v2) ed2->f= 1;
1923
if(ed3->v1==evl->v3) ed3->f= 1;
1926
if(ed4->v1==evl->v4) ed4->f= 1;
1932
if(direct) evl= evl->next;
1933
else evl= evl->prev;
1939
recalc_editnormals();
1941
makeDispList(G.obedit);
1946
static EditVert *findnearestvert(short sel)
1948
EditMesh *em = G.editMesh;
1949
/* if sel==1 the vertices with flag==1 get a disadvantage */
1950
EditVert *eve,*act=0;
1951
static EditVert *acto=0;
1952
short dist=100,temp,mval[2];
1954
if(em->verts.first==0) return 0;
1957
calc_meshverts_ext(); /* drawobject.c */
1959
/* we count from acto->next to last, and from first to acto */
1960
/* does acto exist? */
1961
eve= em->verts.first;
1963
if(eve==acto) break;
1966
if(eve==0) acto= em->verts.first;
1968
if(acto==0) return 0;
1970
/* is there an indicated vertex? part 1 */
1971
getmouseco_areawin(mval);
1975
temp= abs(mval[0]- eve->xs)+ abs(mval[1]- eve->ys);
1976
if( (eve->f & 1)==sel ) temp+=5;
1985
/* is there an indicated vertex? part 2 */
1987
eve= em->verts.first;
1990
temp= abs(mval[0]- eve->xs)+ abs(mval[1]- eve->ys);
1991
if( (eve->f & 1)==sel ) temp+=5;
1997
if(eve== acto) break;
2008
static EditEdge *findnearestedge()
2010
EditMesh *em = G.editMesh;
2011
EditEdge *closest, *eed;
2013
short found=0, mval[2];
2014
float distance[2], v1[2], v2[2], mval2[2];
2016
if(em->edges.first==0) return NULL;
2017
else eed=em->edges.first;
2020
for(eve=em->verts.first; eve; eve=eve->next){
2024
calc_meshverts_ext_f2(); /*sets (eve->f & 2) for vertices that aren't visible*/
2025
getmouseco_areawin(mval);
2028
mval2[0] = (float)mval[0];
2029
mval2[1] = (float)mval[1];
2031
eed=em->edges.first;
2032
/*compare the distance to the rest of the edges and find the closest one*/
2034
/* Are both vertices of the edge ofscreen or either of them hidden? then don't select the edge*/
2035
if( !((eed->v1->f & 2) && (eed->v2->f & 2)) && (eed->v1->h==0 && eed->v2->h==0)){
2036
v1[0] = eed->v1->xs;
2037
v1[1] = eed->v1->ys;
2038
v2[0] = eed->v2->xs;
2039
v2[1] = eed->v2->ys;
2041
distance[1] = PdistVL2Dfl(mval2, v1, v2);
2044
/*do we have to compare it to other distances? */
2046
if (distance[1]<distance[0]){
2047
distance[0]=distance[1];
2048
/*save the current closest edge*/
2052
distance[0]=distance[1];
2062
for(eve=em->verts.first; eve; eve=eve->next){
2066
if(found) return closest;
2070
/* does the same as findnearestedge but both vertices of the edge should be on screen*/
2071
static EditEdge *findnearestvisibleedge()
2073
EditMesh *em = G.editMesh;
2074
EditEdge *closest, *eed;
2076
short found=0, mval[2];
2077
float distance[2], v1[2], v2[2], mval2[2];
2079
if(em->edges.first==0) return NULL;
2080
else eed=em->edges.first;
2083
for(eve=em->verts.first; eve; eve=eve->next){
2086
calc_meshverts_ext_f2(); /*sets (eve->f & 2) for vertices that aren't visible*/
2089
getmouseco_areawin(mval);
2091
mval2[0] = (float)mval[0]; /* cast to float because of the pdist function only taking floats...*/
2092
mval2[1] = (float)mval[1];
2094
eed=em->edges.first;
2095
while(eed) { /* compare the distance to the rest of the edges and find the closest one*/
2096
if( !((eed->v1->f | eed->v2->f) & 2) && (eed->v1->h==0 && eed->v2->h==0) ){ /* only return edges with both vertices on screen */
2097
v1[0] = eed->v1->xs;
2098
v1[1] = eed->v1->ys;
2099
v2[0] = eed->v2->xs;
2100
v2[1] = eed->v2->ys;
2102
distance[1] = PdistVL2Dfl(mval2, v1, v2);
2104
if(distance[1]<50){ /* TODO: make this maximum selecting distance selectable (the same with vertice select?) */
2105
if(found) { /*do we have to compare it to other distances? */
2106
if (distance[1]<distance[0]){
2107
distance[0]=distance[1];
2108
closest=eed; /*save the current closest edge*/
2111
distance[0]=distance[1];
2121
for(eve=em->verts.first; eve; eve=eve->next){
2125
if(found) return closest;
2130
/* this is a template function to demonstrate a loop with drawing...
2131
it is a temporal mode, so use with wisdom! if you can avoid, always better. (ton)
2139
/* uses callback mechanism to draw it all in current area */
2140
scrarea_do_windraw(curarea);
2143
eed= findnearestedge();
2145
/* set window matrix to perspective, default an area returns with buttons transform */
2147
/* make a copy, for safety */
2149
/* multiply with the object transformation */
2150
mymultmatrix(G.obedit->obmat);
2154
glColor3ub(255, 255, 0);
2156
glVertex3fv(eed->v1->co);
2157
glVertex3fv(eed->v2->co);
2161
/* restore matrix transform */
2164
headerprint("We are now in evil edge select mode. Press any key to exit");
2166
/* this also verifies other area/windows for clean swap */
2167
screen_swapbuffers();
2169
/* testing for user input... */
2172
short event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
2174
/* val==0 on key-release event */
2175
if(val && event!=MOUSEY && event!=MOUSEX) {
2179
/* sleep 0.01 second to prevent overload in this poor loop */
2184
/* send event to redraw this window, does header too */
2185
addqueue(curarea->win, REDRAW, 1);
2190
functionality: various loop functions
2191
parameters: mode tells the function what it should do with the loop:
2192
LOOP_SELECT = select
2193
LOOP_CUT = cut in half
2196
void loopoperations(char mode)
2198
EditMesh *em = G.editMesh;
2199
EditVert* look = NULL;
2201
EditEdge *start, *eed, *opposite,*currente, *oldstart;
2202
EditEdge **tagged = NULL,**taggedsrch = NULL,*close;
2204
EditVlak *evl,**percentfacesloop = NULL, *currentvl, *formervl;
2206
short lastface=0, foundedge=0, c=0, tri=0, side=1, totface=0, searching=1, event=0, noface=1;
2207
short skip,nextpos,percentfaces;
2209
int i=0,ect=0,j=0,k=0,cut,smooth,timesthrough=0,inset = 0;
2211
float percentcut, outcut;
2215
if ((G.obedit==0) || (em->faces.first==0)) return;
2217
if(mode==LOOP_CUT)undo_push_mesh("Faceloop Subdivide");
2218
else if(mode==LOOP_SELECT)undo_push_mesh("Faceloop Select");
2220
SetBlenderCursor(BC_VLOOPCURSOR);
2227
/* reset variables */
2228
start=eed=opposite=currente=0;
2229
evl=currentvl=formervl=0;
2231
lastface=foundedge=c=tri=totface=0;
2233
start=findnearestvisibleedge();
2235
/* If the edge doesn't belong to a face, it's not a valid starting edge */
2238
evl=em->faces.first;
2240
if(evl->e1->f & 16){
2244
else if(evl->e2->f & 16){
2248
else if(evl->e3->f & 16){
2252
else if(evl->e4 && (evl->e4->f & 16)){
2261
/* Did we find anything that is selectable? */
2262
if(start && !noface && (oldstart==NULL || start!=oldstart)){
2264
/* If we stay in the neighbourhood of this edge, we don't have to recalculate the loop everytime*/
2268
for(eed=em->edges.first; eed; eed=eed->next){
2269
eed->f &= ~(2|4|8|32|64);
2270
eed->v1->f &= ~(2|8|16);
2271
eed->v2->f &= ~(2|8|16);
2274
for(evl= em->faces.first; evl; evl=evl->next){
2279
/* Tag the starting edge */
2280
start->f |= (2|4|8|64);
2286
/*-----Limit the Search----- */
2287
while(!lastface && c<totface+1){
2289
/*----------Get Loop------------------------*/
2290
tri=foundedge=lastface=0;
2291
evl= em->faces.first;
2292
while(evl && !foundedge && !tri){
2294
if(!(evl->v4)){ /* Exception for triangular faces */
2296
if((evl->e1->f | evl->e2->f | evl->e3->f) & 2){
2300
if(side==1) evl->f |= 4;
2306
if((evl->e1->f | evl->e2->f | evl->e3->f | evl->e4->f) & 2){
2308
if(c==0){ /* just pick a face, doesn't matter wich side of the edge we go to */
2311
if(!(evl->e1->v1->f & 2) && !(evl->e1->v2->f & 2)){
2312
if(evl->e1->v1->h==0 && evl->e1->v2->h==0){
2317
else if(!(evl->e2->v1->f & 2) && !(evl->e2->v2->f & 2)){
2318
if(evl->e2->v1->h==0 && evl->e2->v2->h==0){
2323
else if(!(evl->e3->v1->f & 2) && !(evl->e3->v2->f & 2)){
2324
if(evl->e3->v1->h==0 && evl->e3->v2->h==0){
2329
else if(!(evl->e4->v1->f & 2) && !(evl->e4->v2->f & 2)){
2330
if(evl->e4->v1->h==0 && evl->e4->v2->h==0){
2340
/* mark this side of the edge so we know in which direction we went */
2341
if(side==1) evl->f |= 4;
2346
if(evl!=formervl){ /* prevent going backwards in the loop */
2348
if(!(evl->e1->v1->f & 2) && !(evl->e1->v2->f & 2)){
2349
if(evl->e1->v1->h==0 && evl->e1->v2->h==0){
2354
else if(!(evl->e2->v1->f & 2) && !(evl->e2->v2->f & 2)){
2355
if(evl->e2->v1->h==0 && evl->e2->v2->h==0){
2360
else if(!(evl->e3->v1->f & 2) && !(evl->e3->v2->f & 2)){
2361
if(evl->e3->v1->h==0 && evl->e3->v2->h==0){
2366
else if(!(evl->e4->v1->f & 2) && !(evl->e4->v2->f & 2)){
2367
if(evl->e4->v1->h==0 && evl->e4->v2->h==0){
2380
/*----------END Get Loop------------------------*/
2383
/*----------Decisions-----------------------------*/
2385
/* mark the edge and face as done */
2389
if(opposite->f & 4) lastface=1; /* found the starting edge! close loop */
2391
/* un-set the testflags */
2393
currente->v1->f &= ~2;
2394
currente->v2->f &= ~2;
2396
/* set the opposite edge to be the current edge */
2399
/* set the current face to be the FORMER face (to prevent going backwards in the loop) */
2402
/* set the testflags */
2404
currente->v1->f |= 2;
2405
currente->v2->f |= 2;
2410
/* un-set the testflags */
2412
currente->v1->f &= ~2;
2413
currente->v2->f &= ~2;
2415
/* mark the edge and face as done */
2421
/* is the the first time we've ran out of possible faces?
2422
* try to start from the beginning but in the opposite direction go as far as possible
2428
currente->v1->f |= 2;
2429
currente->v2->f |= 2;
2435
/*----------END Decisions-----------------------------*/
2438
/*-----END Limit the Search----- */
2441
/*------------- Preview lines--------------- */
2443
/* uses callback mechanism to draw it all in current area */
2444
scrarea_do_windraw(curarea);
2446
/* set window matrix to perspective, default an area returns with buttons transform */
2448
/* make a copy, for safety */
2450
/* multiply with the object transformation */
2451
mymultmatrix(G.obedit->obmat);
2453
glColor3ub(255, 255, 0);
2455
if(mode==LOOP_SELECT){
2456
evl= em->faces.first;
2460
if(!(evl->e1->f & 8)){
2462
glVertex3fv(evl->e1->v1->co);
2463
glVertex3fv(evl->e1->v2->co);
2467
if(!(evl->e2->f & 8)){
2469
glVertex3fv(evl->e2->v1->co);
2470
glVertex3fv(evl->e2->v2->co);
2474
if(!(evl->e3->f & 8)){
2476
glVertex3fv(evl->e3->v1->co);
2477
glVertex3fv(evl->e3->v2->co);
2482
if(!(evl->e4->f & 8)){
2484
glVertex3fv(evl->e4->v1->co);
2485
glVertex3fv(evl->e4->v2->co);
2495
evl= em->faces.first;
2504
if(evl->v4)evl->v4->f &= ~8;
2507
cen[a][0]= (evl->e1->v1->co[0] + evl->e1->v2->co[0])/2.0;
2508
cen[a][1]= (evl->e1->v1->co[1] + evl->e1->v2->co[1])/2.0;
2509
cen[a][2]= (evl->e1->v1->co[2] + evl->e1->v2->co[2])/2.0;
2511
evl->e1->v1->f |= 8;
2512
evl->e1->v2->f |= 8;
2516
if((evl->e2->f & 8) && a!=2){
2517
cen[a][0]= (evl->e2->v1->co[0] + evl->e2->v2->co[0])/2.0;
2518
cen[a][1]= (evl->e2->v1->co[1] + evl->e2->v2->co[1])/2.0;
2519
cen[a][2]= (evl->e2->v1->co[2] + evl->e2->v2->co[2])/2.0;
2521
evl->e2->v1->f |= 8;
2522
evl->e2->v2->f |= 8;
2526
if((evl->e3->f & 8) && a!=2){
2527
cen[a][0]= (evl->e3->v1->co[0] + evl->e3->v2->co[0])/2.0;
2528
cen[a][1]= (evl->e3->v1->co[1] + evl->e3->v2->co[1])/2.0;
2529
cen[a][2]= (evl->e3->v1->co[2] + evl->e3->v2->co[2])/2.0;
2531
evl->e3->v1->f |= 8;
2532
evl->e3->v2->f |= 8;
2538
if((evl->e4->f & 8) && a!=2){
2539
cen[a][0]= (evl->e4->v1->co[0] + evl->e4->v2->co[0])/2.0;
2540
cen[a][1]= (evl->e4->v1->co[1] + evl->e4->v2->co[1])/2.0;
2541
cen[a][2]= (evl->e4->v1->co[2] + evl->e4->v2->co[2])/2.0;
2543
evl->e4->v1->f |= 8;
2544
evl->e4->v2->f |= 8;
2549
else{ /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
2550
if(!(evl->v1->f & 8) && evl->v1->h==0){
2551
cen[a][0]= evl->v1->co[0];
2552
cen[a][1]= evl->v1->co[1];
2553
cen[a][2]= evl->v1->co[2];
2556
else if(!(evl->v2->f & 8) && evl->v2->h==0){
2557
cen[a][0]= evl->v2->co[0];
2558
cen[a][1]= evl->v2->co[1];
2559
cen[a][2]= evl->v2->co[2];
2562
else if(!(evl->v3->f & 8) && evl->v3->h==0){
2563
cen[a][0]= evl->v3->co[0];
2564
cen[a][1]= evl->v3->co[1];
2565
cen[a][2]= evl->v3->co[2];
2573
glVertex3fv(cen[0]);
2574
glVertex3fv(cen[1]);
2582
eed=em->edges.first;
2586
glColor3ub(200, 255, 200);
2587
glVertex3fv(eed->v1->co);
2588
glVertex3fv(eed->v2->co);
2597
/* restore matrix transform */
2600
headerprint("LMB to confirm, RMB to cancel");
2602
/* this also verifies other area/windows for clean swap */
2603
screen_swapbuffers();
2605
/*--------- END Preview Lines------------*/
2607
}/*if(start!=NULL){ */
2610
unsigned short val=0;
2611
event= extern_qread(&val); /* extern_qread stores important events for the mainloop to handle */
2613
/* val==0 on key-release event */
2614
if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event == MIDDLEMOUSE)){
2619
}/*while(event!=ESCKEY && event!=RIGHTMOUSE && event!=LEFTMOUSE && event!=RETKEY){*/
2621
/*----------Select Loop------------*/
2622
if(mode==LOOP_SELECT && start!=NULL && ((event==LEFTMOUSE || event==RETKEY) || event == MIDDLEMOUSE || event == BKEY)){
2624
/* If this is a unmodified select, clear the selection */
2625
if(!(G.qual & LR_SHIFTKEY) && !(G.qual & LR_ALTKEY)){
2626
for(evl= em->faces.first;evl;evl=evl->next){
2630
if(evl->v4)evl->v4->f &= !1;
2633
/* Alt was not pressed, so add to the selection */
2634
if(!(G.qual & LR_ALTKEY)){
2635
for(evl= em->faces.first;evl;evl=evl->next){
2640
if(evl->v4)evl->v4->f |= 1;
2644
/* alt was pressed, so subtract from the selection */
2647
for(evl= em->faces.first;evl;evl=evl->next){
2652
if(evl->v4)evl->v4->f &= !1;
2658
/*----------END Select Loop------------*/
2660
/*----------Cut Loop---------------*/
2661
if(mode==LOOP_CUT && start!=NULL && (event==LEFTMOUSE || event==RETKEY)){
2663
/* count the number of edges in the loop */
2664
for(eed=em->edges.first; eed; eed = eed->next){
2669
tagged = MEM_mallocN(ect*sizeof(EditEdge*), "tagged");
2670
taggedsrch = MEM_mallocN(ect*sizeof(EditEdge*), "taggedsrch");
2674
taggedsrch[i] = NULL;
2677
for(eed=em->edges.first; eed; eed = eed->next){
2689
taggedsrch[0] = tagged[0];
2691
while(timesthrough < 2)
2694
while(i < ect){/*Look at the members of the search array to line up cuts*/
2695
if(taggedsrch[i]==NULL)break;
2696
for(j=0;j<ect;j++){ /*Look through the list of tagged verts for connected edges*/
2698
if(taggedsrch[i]->f & 32) /*If this edgee is marked as flipped, use vert 2*/
2699
look = taggedsrch[i]->v2;
2700
else /*else use vert 1*/
2701
look = taggedsrch[i]->v1;
2703
if(taggedsrch[i] == tagged[j])
2704
continue; /*If we are looking at the same edge, skip it*/
2707
for(k=0;k<ect;k++) {
2708
if(taggedsrch[k] == NULL) /*go to empty part of search list without finding*/
2710
if(tagged[j] == taggedsrch[k]){ /*We found a match already in the list*/
2718
if(findedgelist(look,tagged[j]->v2)){
2719
while(nextpos < ect){ /*Find the first open spot in the search array*/
2720
if(taggedsrch[nextpos] == NULL){
2721
taggedsrch[nextpos] = tagged[j]; /*put tagged[j] in it*/
2722
taggedsrch[nextpos]->f |= 32;
2729
} /* End else if connected to vert 2*/
2730
else if(findedgelist(look,tagged[j]->v1)){ /*If our vert is connected to vert 1 */
2731
while(nextpos < ect){ /*Find the first open spot in the search array */
2732
if(taggedsrch[nextpos] == NULL){
2733
taggedsrch[nextpos] = tagged[j]; /*put tagged[j] in it*/
2746
}/* End Outer For (j)*/
2748
} /* End while(j<ect)*/
2750
} /*end while timesthrough */
2758
/* Count the Number of Faces in the selected loop*/
2760
for(evl= em->faces.first; evl ;evl=evl->next){
2767
/* create a dynamic array for those face pointers */
2768
percentfacesloop = MEM_mallocN(percentfaces*sizeof(EditVlak*), "percentage");
2770
/* put those faces in the array */
2772
for(evl= em->faces.first; evl ;evl=evl->next){
2775
percentfacesloop[i] = evl;
2782
/* For the % calculation */
2784
float labda, rc[2], len, slen=0.0;
2785
float v1[2], v2[2], v3[2];
2787
/*------------- Percent Cut Preview Lines--------------- */
2788
scrarea_do_windraw(curarea);
2791
mymultmatrix(G.obedit->obmat);
2792
glColor3ub(0, 255, 255);
2794
/*Put the preview lines where they should be for the percentage selected.*/
2796
for(i=0;i<percentfaces;i++){
2797
evl = percentfacesloop[i];
2798
for(eed = em->edges.first; eed; eed=eed->next){
2799
if(eed->f & 64){ /* color the starting edge */
2802
glColor3ub(200, 255, 200);
2803
glVertex3fv(eed->v1->co);
2804
glVertex3fv(eed->v2->co);
2810
glColor3ub(255,0,255);
2813
glVertex3fv(eed->v2->co);
2815
glVertex3fv(eed->v1->co);
2819
/*Get Starting Edge Length*/
2820
slen = sqrt((eed->v1->co[0]-eed->v2->co[0])*(eed->v1->co[0]-eed->v2->co[0])+
2821
(eed->v1->co[1]-eed->v2->co[1])*(eed->v1->co[1]-eed->v2->co[1])+
2822
(eed->v1->co[2]-eed->v2->co[2])*(eed->v1->co[2]-eed->v2->co[2]));
2827
glColor3ub(0,255,255);
2836
if(evl->v4)evl->v4->f &= ~8;
2844
cen[a][0]= evl->e1->v1->co[0] - ((evl->e1->v1->co[0] - evl->e1->v2->co[0]) * (pct));
2845
cen[a][1]= evl->e1->v1->co[1] - ((evl->e1->v1->co[1] - evl->e1->v2->co[1]) * (pct));
2846
cen[a][2]= evl->e1->v1->co[2] - ((evl->e1->v1->co[2] - evl->e1->v2->co[2]) * (pct));
2847
evl->e1->v1->f |= 8;
2848
evl->e1->v2->f |= 8;
2851
if((evl->e2->f & 8) && a!=2)
2858
cen[a][0]= evl->e2->v1->co[0] - ((evl->e2->v1->co[0] - evl->e2->v2->co[0]) * (pct));
2859
cen[a][1]= evl->e2->v1->co[1] - ((evl->e2->v1->co[1] - evl->e2->v2->co[1]) * (pct));
2860
cen[a][2]= evl->e2->v1->co[2] - ((evl->e2->v1->co[2] - evl->e2->v2->co[2]) * (pct));
2862
evl->e2->v1->f |= 8;
2863
evl->e2->v2->f |= 8;
2867
if((evl->e3->f & 8) && a!=2){
2873
cen[a][0]= evl->e3->v1->co[0] - ((evl->e3->v1->co[0] - evl->e3->v2->co[0]) * (pct));
2874
cen[a][1]= evl->e3->v1->co[1] - ((evl->e3->v1->co[1] - evl->e3->v2->co[1]) * (pct));
2875
cen[a][2]= evl->e3->v1->co[2] - ((evl->e3->v1->co[2] - evl->e3->v2->co[2]) * (pct));
2877
evl->e3->v1->f |= 8;
2878
evl->e3->v2->f |= 8;
2884
if((evl->e4->f & 8) && a!=2){
2890
cen[a][0]= evl->e4->v1->co[0] - ((evl->e4->v1->co[0] - evl->e4->v2->co[0]) * (pct));
2891
cen[a][1]= evl->e4->v1->co[1] - ((evl->e4->v1->co[1] - evl->e4->v2->co[1]) * (pct));
2892
cen[a][2]= evl->e4->v1->co[2] - ((evl->e4->v1->co[2] - evl->e4->v2->co[2]) * (pct));
2894
evl->e4->v1->f |= 8;
2895
evl->e4->v2->f |= 8;
2900
else { /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
2901
if(!(evl->v1->f & 8) && evl->v1->h==0){
2902
cen[a][0]= evl->v1->co[0];
2903
cen[a][1]= evl->v1->co[1];
2904
cen[a][2]= evl->v1->co[2];
2907
else if(!(evl->v2->f & 8) && evl->v2->h==0){
2908
cen[a][0]= evl->v2->co[0];
2909
cen[a][1]= evl->v2->co[1];
2910
cen[a][2]= evl->v2->co[2];
2913
else if(!(evl->v3->f & 8) && evl->v3->h==0){
2914
cen[a][0]= evl->v3->co[0];
2915
cen[a][1]= evl->v3->co[1];
2916
cen[a][2]= evl->v3->co[2];
2924
glVertex3fv(cen[0]);
2925
glVertex3fv(cen[1]);
2930
}/* end preview line drawing */
2932
glColor3ub(0,128,255);
2941
if(evl->v4)evl->v4->f &= ~8;
2946
nlen = sqrt((evl->e1->v1->co[0] - evl->e1->v2->co[0])*(evl->e1->v1->co[0] - evl->e1->v2->co[0])+
2947
(evl->e1->v1->co[1] - evl->e1->v2->co[1])*(evl->e1->v1->co[1] - evl->e1->v2->co[1])+
2948
(evl->e1->v1->co[2] - evl->e1->v2->co[2])*(evl->e1->v1->co[2] - evl->e1->v2->co[2]));
2949
npct = (percentcut*slen)/nlen;
2950
if(npct >= 1) npct = 1;
2951
if(evl->e1->f & 32) npct = 1-npct;
2953
cen[a][0]= evl->e1->v1->co[0] - ((evl->e1->v1->co[0] - evl->e1->v2->co[0]) * (npct));
2954
cen[a][1]= evl->e1->v1->co[1] - ((evl->e1->v1->co[1] - evl->e1->v2->co[1]) * (npct));
2955
cen[a][2]= evl->e1->v1->co[2] - ((evl->e1->v1->co[2] - evl->e1->v2->co[2]) * (npct));
2957
evl->e1->f1 = 32768*(npct);
2958
evl->e1->v1->f |= 8;
2959
evl->e1->v2->f |= 8;
2962
if((evl->e2->f & 8) && a!=2)
2966
nlen = sqrt((evl->e2->v1->co[0] - evl->e2->v2->co[0])*(evl->e2->v1->co[0] - evl->e2->v2->co[0])+
2967
(evl->e2->v1->co[1] - evl->e2->v2->co[1])*(evl->e2->v1->co[1] - evl->e2->v2->co[1])+
2968
(evl->e2->v1->co[2] - evl->e2->v2->co[2])*(evl->e2->v1->co[2] - evl->e2->v2->co[2]));
2969
npct = (percentcut*slen)/nlen;
2970
if(npct >= 1) npct = 1;
2971
if(evl->e2->f & 32) npct = 1-npct;
2973
cen[a][0]= evl->e2->v1->co[0] - ((evl->e2->v1->co[0] - evl->e2->v2->co[0]) * (npct));
2974
cen[a][1]= evl->e2->v1->co[1] - ((evl->e2->v1->co[1] - evl->e2->v2->co[1]) * (npct));
2975
cen[a][2]= evl->e2->v1->co[2] - ((evl->e2->v1->co[2] - evl->e2->v2->co[2]) * (npct));
2977
evl->e2->f1 = 32768*(npct);
2978
evl->e2->v1->f |= 8;
2979
evl->e2->v2->f |= 8;
2982
if((evl->e3->f & 8) && a!=2){
2985
nlen = sqrt((evl->e3->v1->co[0] - evl->e3->v2->co[0])*(evl->e3->v1->co[0] - evl->e3->v2->co[0])+
2986
(evl->e3->v1->co[1] - evl->e3->v2->co[1])*(evl->e3->v1->co[1] - evl->e3->v2->co[1])+
2987
(evl->e3->v1->co[2] - evl->e3->v2->co[2])*(evl->e3->v1->co[2] - evl->e3->v2->co[2]));
2988
npct = (percentcut*slen)/nlen;
2989
if(npct >= 1) npct = 1;
2990
if(evl->e3->f & 32) npct = 1-npct;
2992
cen[a][0]= evl->e3->v1->co[0] - ((evl->e3->v1->co[0] - evl->e3->v2->co[0]) * (npct));
2993
cen[a][1]= evl->e3->v1->co[1] - ((evl->e3->v1->co[1] - evl->e3->v2->co[1]) * (npct));
2994
cen[a][2]= evl->e3->v1->co[2] - ((evl->e3->v1->co[2] - evl->e3->v2->co[2]) * (npct));
2996
evl->e3->f1 = 32768*(npct);
2997
evl->e3->v1->f |= 8;
2998
evl->e3->v2->f |= 8;
3003
if((evl->e4->f & 8) && a!=2){
3006
nlen = sqrt((evl->e4->v1->co[0] - evl->e4->v2->co[0])*(evl->e4->v1->co[0] - evl->e4->v2->co[0])+
3007
(evl->e4->v1->co[1] - evl->e4->v2->co[1])*(evl->e4->v1->co[1] - evl->e4->v2->co[1])+
3008
(evl->e4->v1->co[2] - evl->e4->v2->co[2])*(evl->e4->v1->co[2] - evl->e4->v2->co[2]));
3009
npct = (percentcut*slen)/nlen;
3010
if(npct >= 1) npct = 1;
3011
if(evl->e4->f & 32) npct = 1-npct;
3013
cen[a][0]= evl->e4->v1->co[0] - ((evl->e4->v1->co[0] - evl->e4->v2->co[0]) * (npct));
3014
cen[a][1]= evl->e4->v1->co[1] - ((evl->e4->v1->co[1] - evl->e4->v2->co[1]) * (npct));
3015
cen[a][2]= evl->e4->v1->co[2] - ((evl->e4->v1->co[2] - evl->e4->v2->co[2]) * (npct));
3017
evl->e4->f1 = 32768*(npct);
3018
evl->e4->v1->f |= 8;
3019
evl->e4->v2->f |= 8;
3023
else { /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
3024
if(!(evl->v1->f & 8) && evl->v1->h==0){
3025
cen[a][0]= evl->v1->co[0];
3026
cen[a][1]= evl->v1->co[1];
3027
cen[a][2]= evl->v1->co[2];
3030
else if(!(evl->v2->f & 8) && evl->v2->h==0){
3031
cen[a][0]= evl->v2->co[0];
3032
cen[a][1]= evl->v2->co[1];
3033
cen[a][2]= evl->v2->co[2];
3036
else if(!(evl->v3->f & 8) && evl->v3->h==0){
3037
cen[a][0]= evl->v3->co[0];
3038
cen[a][1]= evl->v3->co[1];
3039
cen[a][2]= evl->v3->co[2];
3047
glVertex3fv(cen[0]);
3048
glVertex3fv(cen[1]);
3055
/* restore matrix transform */
3059
/*--------- END Preview Lines------------*/
3062
unsigned short val=0;
3063
event= extern_qread(&val); /* extern_qread stores important events for the mainloop to handle */
3064
/* val==0 on key-release event */
3066
if(val && (event==SKEY))
3068
if(smooth)smooth = 0;
3072
if(val && (event==PKEY))
3078
if(val && (event==FKEY))
3081
for(ct = 0; ct < ect; ct++){
3082
if(tagged[ct]->f & 32)
3083
tagged[ct]->f &= ~32;
3085
tagged[ct]->f |= 32;
3089
if(val && (event == MIDDLEMOUSE))
3094
else if(val && (event==LEFTMOUSE || event==RETKEY))
3099
if(val && (event==ESCKEY || event==RIGHTMOUSE ))
3108
/* Determine the % on wich the loop should be cut */
3109
getmouseco_areawin(mval);
3110
v1[0]=(float)mval[0];
3111
v1[1]=(float)mval[1];
3113
v2[0]=(float)start->v1->xs;
3114
v2[1]=(float)start->v1->ys;
3116
v3[0]=(float)start->v2->xs;
3117
v3[1]=(float)start->v2->ys;
3121
len= rc[0]*rc[0]+ rc[1]*rc[1];
3123
labda= ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
3126
if(labda<=0.0) labda=0.0;
3127
else if(labda>=1.0)labda=1.0;
3132
percentcut = 1.0-percentcut;
3138
if (G.qual & LR_SHIFTKEY){
3140
percentcut = (int)(percentcut*100.0)/100.0;
3142
else if (G.qual & LR_CTRLKEY)
3143
percentcut = (int)(percentcut*10.0)/10.0;
3145
outcut = (percentcut*100.0);
3147
/* Build the Header Line */
3150
sprintf(mesg,"Cut: %0.2f%% ",slen*percentcut);
3152
sprintf(mesg,"Cut: %0.2f%% ",outcut);
3156
sprintf(mesg,"%s| (f)lip side | (s)mooth on |",mesg);
3158
sprintf(mesg,"%s| (f)lip side | (s)mooth off |",mesg);
3161
sprintf(mesg,"%s (p)roportional on ",mesg);
3163
sprintf(mesg,"%s (p)roportional off",mesg);
3167
screen_swapbuffers();
3171
/* Now that we have selected a cut %, mark the edges for cutting. */
3173
for(eed = em->edges.first; eed; eed=eed->next){
3174
if(percentcut == 1.0)
3175
percentcut = 0.9999;
3176
else if(percentcut == 0.0)
3177
percentcut = 0.0001;
3179
if(eed->f & 32)/* Need to offset by a const. (0.5/32768) for consistant roundoff */
3180
eed->f1 = 32768*(1.0-percentcut - 0.0000153);
3182
eed->f1 = 32768*(percentcut + 0.0000153);
3186
/*-------------------------------------*/
3189
subdivideflag(8, 0, B_KNIFE | B_PERCENTSUBD | B_SMOOTH); /* B_KNIFE tells subdivide that edgeflags are already set */
3191
subdivideflag(8, 0, B_KNIFE | B_PERCENTSUBD); /* B_KNIFE tells subdivide that edgeflags are already set */
3193
for(eed = em->edges.first; eed; eed=eed->next){
3194
if(eed->v1->f & 16) eed->v1->f |= 1;
3195
else eed->v1->f &= ~1;
3197
if(eed->v2->f & 16) eed->v2->f |= 1;
3198
else eed->v2->f &= ~1;
3202
/*----------END Cut Loop-----------------------------*/
3207
for(eed = em->edges.first; eed; eed=eed->next){
3208
eed->f &= ~(2|4|8|32|64);
3209
eed->v1->f &= ~(2|16);
3210
eed->v2->f &= ~(2|16);
3213
for(evl= em->faces.first; evl; evl=evl->next){
3222
MEM_freeN(taggedsrch);
3223
if(percentfacesloop)
3224
MEM_freeN(percentfacesloop);
3226
/* send event to redraw this window, does header too */
3227
SetBlenderCursor(SYSCURSOR);
3228
addqueue(curarea->win, REDRAW, 1);
3231
void edge_select(void)
3233
EditMesh *em = G.editMesh;
3234
EditEdge *closest=0;
3236
closest=findnearestedge();
3238
if(closest){ /* Did we find anything that is selectable?*/
3240
if( (G.qual & LR_SHIFTKEY)==0) {
3243
undo_push_mesh("Edge select");
3245
for(eve= em->verts.first; eve; eve= eve->next) eve->f&= ~1;
3248
closest->v1->f |= 1;
3249
closest->v2->f |= 1;
3252
/* both of the vertices are selected: deselect both*/
3253
if((closest->v1->f & 1) && (closest->v2->f & 1) ){
3254
closest->v1->f &= ~1;
3255
closest->v2->f &= ~1;
3259
closest->v1->f |= 1;
3260
closest->v2->f |= 1;
3264
allqueue(REDRAWVIEW3D, 0);
3268
static void draw_vertices_special(int mode, EditVert *act) /* teken = draw */
3270
/* (only this view, no other windows) */
3271
/* hackish routine for visual speed:
3272
* mode 0: deselect the selected ones, draw them, except act
3273
* mode 1: only draw act
3275
EditMesh *em = G.editMesh;
3277
float size= BIF_GetThemeValuef(TH_VERTEX_SIZE);
3284
mymultmatrix(G.obedit->obmat);
3287
BIF_ThemeColor(TH_VERTEX);
3289
/* set zbuffer on, its default off outside main drawloops */
3290
if(G.vd->drawtype > OB_WIRE) {
3292
glEnable(GL_DEPTH_TEST);
3296
eve= (EditVert *)em->verts.first;
3299
if(eve!=act && (eve->f & 1)) {
3301
glVertex3fv(eve->co);
3308
glDisable(GL_DEPTH_TEST);
3312
/* draw active vertex */
3313
if(act->f & 1) BIF_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
3314
else BIF_GetThemeColor3ubv(TH_VERTEX, col);
3316
glColor3ub(col[0], col[1], col[2]);
3319
glVertex3fv(act->co);
3328
void mouse_mesh(void)
3332
if(G.qual & LR_ALTKEY) {
3333
if (G.qual & LR_CTRLKEY) edge_select();
3337
act= findnearestvert(1);
3340
glDrawBuffer(GL_FRONT);
3342
undo_push_mesh("Vertex select");
3344
if( (act->f & 1)==0) act->f+= 1;
3345
else if(G.qual & LR_SHIFTKEY) act->f-= 1;
3347
if((G.qual & LR_SHIFTKEY)==0) {
3348
draw_vertices_special(0, act);
3350
else draw_vertices_special(1, act);
3355
glDrawBuffer(GL_BACK);
3357
/* signal that frontbuf differs from back */
3358
curarea->win_swap= WIN_FRONT_OK;
3360
if(G.f & (G_FACESELECT|G_DRAWFACES|G_DRAWEDGES)) {
3361
/* update full view later on */
3362
allqueue(REDRAWVIEW3D, 0);
3364
else allqueue(REDRAWVIEW3D, curarea->win); // all windows except this one
3367
rightmouse_transform();
3371
static void selectconnectedAll(void)
3373
EditMesh *em = G.editMesh;
3376
short flag=1,toggle=0;
3378
if(em->edges.first==0) return;
3380
undo_push_mesh("Select Connected (All)");
3385
if(toggle & 1) eed= em->edges.first;
3386
else eed= em->edges.last;
3392
if( (v2->f & 1)==0 ) {
3397
else if(v2->f & 1) {
3398
if( (v1->f & 1)==0 ) {
3404
if(toggle & 1) eed= eed->next;
3405
else eed= eed->prev;
3410
allqueue(REDRAWVIEW3D, 0);
3414
void selectconnected_mesh(int qual)
3416
EditMesh *em = G.editMesh;
3417
EditVert *eve,*v1,*v2,*act= 0;
3419
short flag=1,sel,toggle=0;
3421
if(em->edges.first==0) return;
3423
if(qual & LR_CTRLKEY) {
3424
selectconnectedAll();
3429
if(qual & LR_SHIFTKEY) sel=2;
3431
act= findnearestvert(sel-2);
3433
error(" Nothing indicated ");
3437
undo_push_mesh("Select linked");
3438
/* clear test flags */
3439
eve= em->verts.first;
3444
act->f= (act->f & ~3) | sel;
3449
if(toggle & 1) eed= em->edges.first;
3450
else eed= em->edges.last;
3456
if( (v2->f & 2)==0 ) {
3457
v2->f= (v2->f & ~3) | sel;
3461
else if(v2->f & 2) {
3462
if( (v1->f & 2)==0 ) {
3463
v1->f= (v1->f & ~3) | sel;
3468
if(toggle & 1) eed= eed->next;
3469
else eed= eed->prev;
3474
allqueue(REDRAWVIEW3D, 0);
3478
short extrudeflag(short flag,short type)
3480
/* when type=1 old extrusion faces are removed (for spin etc) */
3481
/* all verts with (flag & 'flag'): extrude */
3482
/* from old verts, 'flag' is cleared, in new ones it is set */
3483
EditMesh *em = G.editMesh;
3484
EditVert *eve, *v1, *v2, *v3, *v4, *nextve;
3485
EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
3486
EditVlak *evl, *evl2, *nextvl;
3487
short sel=0, deloud= 0, smooth= 0;
3489
if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
3491
/* clear vert flag f1, we use this to detext a loose selected vertice */
3492
eve= em->verts.first;
3494
if(eve->f & flag) eve->f1= 1;
3498
/* clear edges counter flag, if selected we set it at 1 */
3499
eed= em->edges.first;
3501
if( (eed->v1->f & flag) && (eed->v2->f & flag) ) {
3508
eed->f1= 1; /* this indicates it is an 'old' edge (in this routine we make new ones) */
3513
/* we set a flag in all selected faces, and increase the associated edge counters */
3515
evl= em->faces.first;
3519
if (evl->flag & ME_SMOOTH) {
3520
if (vlakselectedOR(evl, 1)) smooth= 1;
3523
if(vlakselectedAND(evl, flag)) {
3529
if(e1->f < 3) e1->f++;
3530
if(e2->f < 3) e2->f++;
3531
if(e3->f < 3) e3->f++;
3532
if(e4 && e4->f < 3) e4->f++;
3535
else if(vlakselectedOR(evl, flag)) {
3541
if( (e1->v1->f & flag) && (e1->v2->f & flag) ) e1->f1= 2;
3542
if( (e2->v1->f & flag) && (e2->v2->f & flag) ) e2->f1= 2;
3543
if( (e3->v1->f & flag) && (e3->v2->f & flag) ) e3->f1= 2;
3544
if( e4 && (e4->v1->f & flag) && (e4->v2->f & flag) ) e4->f1= 2;
3550
/* set direction of edges */
3551
evl= em->faces.first;
3555
if(evl->e1->v1 == evl->v1) evl->e1->dir= 0;
3556
else evl->e1->dir= 1;
3559
if(evl->e2->v1 == evl->v2) evl->e2->dir= 0;
3560
else evl->e2->dir= 1;
3563
if(evl->e3->v1 == evl->v3) evl->e3->dir= 0;
3564
else evl->e3->dir= 1;
3566
if(evl->e4 && evl->e4->f==2) {
3567
if(evl->e4->v1 == evl->v4) evl->e4->dir= 0;
3568
else evl->e4->dir= 1;
3575
/* the current state now is:
3576
eve->f1==1: loose selected vertex
3578
eed->f==0 : edge is not selected, no extrude
3579
eed->f==1 : edge selected, is not part of a face, extrude
3580
eed->f==2 : edge selected, is part of 1 face, extrude
3581
eed->f==3 : edge selected, is part of more faces, no extrude
3583
eed->f1==0: new edge
3584
eed->f1==1: edge selected, is part of selected face, when eed->f==3: remove
3585
eed->f1==2: edge selected, is not part of a selected face
3587
evl->f==1 : duplicate this face
3590
/* copy all selected vertices, */
3591
/* write pointer to new vert in old struct at eve->vn */
3592
eve= em->verts.last;
3594
eve->f&= ~128; /* clear, for later test for loose verts */
3599
VECCOPY(v1->co, eve->co);
3608
if(sel==0) return 0;
3610
/* all edges with eed->f==1 or eed->f==2 become faces */
3611
/* if deloud==1 then edges with eed->f>2 are removed */
3612
eed= em->edges.last;
3616
eed->v1->f|=128; /* = no loose vert! */
3619
if( (eed->f==1 || eed->f==2) ) {
3620
if(eed->f1==2) deloud=1;
3622
if(eed->dir==1) evl2= addvlaklist(eed->v1, eed->v2, eed->v2->vn, eed->v1->vn, NULL);
3623
else evl2= addvlaklist(eed->v2, eed->v1, eed->v1->vn, eed->v2->vn, NULL);
3624
if (smooth) evl2->flag |= ME_SMOOTH;
3630
eed= em->edges.first;
3633
if(eed->f==3 && eed->f1==1) {
3640
/* duplicate faces, if necessart remove old ones */
3641
evl= em->faces.first;
3649
if(evl->v4) v4= evl->v4->vn; else v4= 0;
3651
evl2= addvlaklist(v1, v2, v3, v4, evl);
3654
BLI_remlink(&em->faces, evl);
3657
if (smooth) evl2->flag |= ME_SMOOTH;
3661
/* for all vertices with eve->vn!=0
3662
if eve->f1==1: make edge
3663
if flag!=128 : if deloud==1: remove
3665
eve= em->verts.last;
3669
if(eve->f1==1) addedgelist(eve,eve->vn);
3670
else if( (eve->f & 128)==0) {
3672
BLI_remlink(&em->verts,eve);
3678
if(eve) eve->f&= ~128;
3686
void rotateflag(short flag, float *cent, float rotmat[][3])
3688
/* all verts with (flag & 'flag') rotate */
3689
EditMesh *em = G.editMesh;
3692
eve= em->verts.first;
3695
eve->co[0]-=cent[0];
3696
eve->co[1]-=cent[1];
3697
eve->co[2]-=cent[2];
3698
Mat3MulVecfl(rotmat,eve->co);
3699
eve->co[0]+=cent[0];
3700
eve->co[1]+=cent[1];
3701
eve->co[2]+=cent[2];
3707
void translateflag(short flag, float *vec)
3709
/* all verts with (flag & 'flag') translate */
3710
EditMesh *em = G.editMesh;
3713
eve= em->verts.first;
3724
short removedoublesflag(short flag, float limit) /* return amount */
3726
EditMesh *em = G.editMesh;
3727
/* all verts with (flag & 'flag') are being evaluated */
3728
EditVert *eve, *v1, *nextve;
3729
EditEdge *eed, *e1, *nexted;
3730
EditVlak *evl, *nextvl;
3731
struct xvertsort *sortblock, *sb, *sb1;
3732
struct vlaksort *vlsortblock, *vsb, *vsb1;
3734
int a, b, test, aantal;
3736
/* flag 128 is cleared, count */
3737
eve= em->verts.first;
3741
if(eve->f & flag) aantal++;
3744
if(aantal==0) return 0;
3746
/* allocate memory and qsort */
3747
sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub");
3748
eve= em->verts.first;
3751
sb->x= eve->co[0]+eve->co[1]+eve->co[2];
3757
qsort(sortblock, aantal, sizeof(struct xvertsort), vergxco);
3759
/* test for doubles */
3761
for(a=0; a<aantal; a++) {
3763
if( (eve->f & 128)==0 ) {
3765
for(b=a+1; b<aantal; b++) {
3766
/* first test: simpel dist */
3767
dist= sb1->x - sb->x;
3768
if(dist > limit) break;
3770
/* second test: is vertex allowed */
3772
if( (v1->f & 128)==0 ) {
3774
dist= fabs(v1->co[0]-eve->co[0]);
3776
dist= fabs(v1->co[1]-eve->co[1]);
3778
dist= fabs(v1->co[2]-eve->co[2]);
3791
MEM_freeN(sortblock);
3793
/* test edges and insert again */
3794
eed= em->edges.first;
3799
eed= em->edges.last;
3804
if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
3807
if(eed->v1->f & 128) eed->v1= eed->v1->vn;
3808
if(eed->v2->f & 128) eed->v2= eed->v2->vn;
3810
e1= addedgelist(eed->v1,eed->v2);
3813
if(e1!=eed) free_editedge(eed);
3819
/* first count amount of test faces */
3820
evl= (struct EditVlak *)em->faces.first;
3824
if(evl->v1->f & 128) evl->f= 1;
3825
else if(evl->v2->f & 128) evl->f= 1;
3826
else if(evl->v3->f & 128) evl->f= 1;
3827
else if(evl->v4 && (evl->v4->f & 128)) evl->f= 1;
3829
if(evl->f==1) aantal++;
3833
/* test faces for double vertices, and if needed remove them */
3834
evl= (struct EditVlak *)em->faces.first;
3839
if(evl->v1->f & 128) evl->v1= evl->v1->vn;
3840
if(evl->v2->f & 128) evl->v2= evl->v2->vn;
3841
if(evl->v3->f & 128) evl->v3= evl->v3->vn;
3842
if(evl->v4 && (evl->v4->f & 128)) evl->v4= evl->v4->vn;
3845
if(evl->v1==evl->v2) test+=1;
3846
if(evl->v2==evl->v3) test+=2;
3847
if(evl->v3==evl->v1) test+=4;
3848
if(evl->v4==evl->v1) test+=8;
3849
if(evl->v3==evl->v4) test+=16;
3850
if(evl->v2==evl->v4) test+=32;
3854
if(test==1 || test==2) {
3860
else if(test==8 || test==16) {
3865
BLI_remlink(&em->faces, evl);
3871
BLI_remlink(&em->faces, evl);
3878
/* set edge pointers */
3879
evl->e1= findedgelist(evl->v1, evl->v2);
3880
evl->e2= findedgelist(evl->v2, evl->v3);
3882
evl->e3= findedgelist(evl->v3, evl->v1);
3886
evl->e3= findedgelist(evl->v3, evl->v4);
3887
evl->e4= findedgelist(evl->v4, evl->v1);
3894
/* double faces: sort block */
3895
/* count again, now all selected faces */
3897
evl= em->faces.first;
3900
if(vlakselectedAND(evl, 1)) {
3908
/* double faces: sort block */
3909
vsb= vlsortblock= MEM_mallocN(sizeof(struct vlaksort)*aantal, "sortremovedoub");
3910
evl= em->faces.first;
3913
if(evl->v4) vsb->x= (long) MIN4( (long)evl->v1, (long)evl->v2, (long)evl->v3, (long)evl->v4);
3914
else vsb->x= (long) MIN3( (long)evl->v1, (long)evl->v2, (long)evl->v3);
3922
qsort(vlsortblock, aantal, sizeof(struct vlaksort), vergvlak);
3925
for(a=0; a<aantal; a++) {
3927
if( (evl->f & 128)==0 ) {
3930
for(b=a+1; b<aantal; b++) {
3932
/* first test: same pointer? */
3933
if(vsb->x != vsb1->x) break;
3935
/* second test: is test permitted? */
3937
if( (evl->f & 128)==0 ) {
3938
if( comparevlak(evl, vsb->evl)) evl->f |= 128;
3947
MEM_freeN(vlsortblock);
3949
/* remove double faces */
3950
evl= (struct EditVlak *)em->faces.first;
3954
BLI_remlink(&em->faces, evl);
3961
/* remove double vertices */
3963
eve= (struct EditVert *)em->verts.first;
3969
BLI_remlink(&em->verts, eve);
3975
return a; /* amount */
3978
void xsortvert_flag(int flag)
3980
EditMesh *em = G.editMesh;
3981
/* all verts with (flag & 'flag') are sorted */
3983
struct xvertsort *sortblock, *sb;
3988
eve= em->verts.first;
3991
if(eve->f & flag) aantal++;
3994
if(aantal==0) return;
3996
undo_push_mesh("Xsort");
3998
/* allocate memory and sort */
3999
sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub");
4000
eve= em->verts.first;
4009
qsort(sortblock, aantal, sizeof(struct xvertsort), vergxco);
4011
/* make temporal listbase */
4012
tbase.first= tbase.last= 0;
4016
BLI_remlink(&em->verts, eve);
4017
BLI_addtail(&tbase, eve);
4021
addlisttolist(&em->verts, &tbase);
4023
MEM_freeN(sortblock);
4027
void hashvert_flag(int flag)
4029
/* switch vertex order using hash table */
4030
EditMesh *em = G.editMesh;
4032
struct xvertsort *sortblock, *sb, onth, *newsort;
4037
eve= em->verts.first;
4040
if(eve->f & flag) aantal++;
4043
if(aantal==0) return;
4045
undo_push_mesh("Hash");
4047
/* allocate memory */
4048
sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*aantal,"sortremovedoub");
4049
eve= em->verts.first;
4061
for(a=0; a<aantal; a++, sb++) {
4062
b= aantal*BLI_drand();
4063
if(b>=0 && b<aantal) {
4064
newsort= sortblock+b;
4071
/* make temporal listbase */
4072
tbase.first= tbase.last= 0;
4076
BLI_remlink(&em->verts, eve);
4077
BLI_addtail(&tbase, eve);
4081
addlisttolist(&em->verts, &tbase);
4083
MEM_freeN(sortblock);
4086
static unsigned int cpack_fact(unsigned int col1, unsigned int col2, float fact)
4088
char *cp1, *cp2, *cp;
4092
fact1=1-fact; /*result is fact% col1 and (1-fact) % col2 */
4098
cp[0]= fact*cp1[0]+fact1*cp2[0];
4099
cp[1]= fact*cp1[1]+fact1*cp2[1];
4100
cp[2]= fact*cp1[2]+fact1*cp2[2];
4101
cp[3]= fact*cp1[3]+fact1*cp2[3];
4107
static void uv_half(float *uv, float *uv1, float *uv2)
4109
uv[0]= (uv1[0]+uv2[0])/2.0;
4110
uv[1]= (uv1[1]+uv2[1])/2.0;
4114
static void uv_quart(float *uv, float *uv1)
4116
uv[0]= (uv1[0]+uv1[2]+uv1[4]+uv1[6])/4.0;
4117
uv[1]= (uv1[1]+uv1[3]+uv1[5]+uv1[7])/4.0;
4120
static void set_wuv(int tot, EditVlak *evl, int v1, int v2, int v3, int v4)
4122
/* this weird function only to be used for subdivide, the 'w' in the name has no meaning! */
4123
float *uv, uvo[4][2];
4124
unsigned int *col, colo[4], col1, col2;
4126
/* Numbers corespond to verts (corner points), */
4127
/* edge->vn's (center edges), the Center */
4128
memcpy(uvo, evl->tf.uv, sizeof(uvo)); /* And the quincunx points of a face */
4129
uv= evl->tf.uv[0]; /* as shown here: */
4131
memcpy(colo, evl->tf.col, sizeof(colo)); /* 10 13 */
4132
col= evl->tf.col; /* 6 9 8 */
4134
if(tot==4) { /* 3 7 4 */
4135
for(a=0; a<4; a++, uv+=2, col++) {
4137
else if(a==1) v= v2;
4138
else if(a==2) v= v3;
4141
if(a==3 && v4==0) break;
4149
uv_half(uv, uvo[3], uvo[0]);
4150
*col= cpack_fact(colo[3], colo[0], 0.5);
4153
uv_quart(uv, uvo[0]);
4154
col1= cpack_fact(colo[1], colo[0], 0.5);
4155
col2= cpack_fact(colo[2], colo[3], 0.5);
4156
*col= cpack_fact(col1, col2, 0.5);
4158
/* Cases for adjacent edge square subdivide Real voodoo */
4159
/* 1/2 closest corner + 1/4 adjacent corners */
4160
else if (v==10){ /* case test==3 in subdivideflag() */
4161
uv[0]=(2*uvo[1][0]+uvo[0][0]+uvo[2][0])/4;
4162
uv[1]=(2*uvo[1][1]+uvo[0][1]+uvo[2][1])/4;
4163
col1= cpack_fact(colo[1], colo[0], 0.75);
4164
col2= cpack_fact(colo[2], colo[3], 0.75);
4165
*col= cpack_fact(col1, col2, 0.75);
4167
else if (v==11) { /* case of test==6 */
4168
uv[0]=(2*uvo[2][0]+uvo[1][0]+uvo[3][0])/4;
4169
uv[1]=(2*uvo[2][1]+uvo[1][1]+uvo[3][1])/4;
4170
col1= cpack_fact(colo[1], colo[0], 0.75);
4171
col2= cpack_fact(colo[2], colo[3], 0.75);
4172
*col= cpack_fact(col1, col2, 0.25);
4174
else if (v==12) { /* case of test==12 */
4175
uv[0]=(2*uvo[3][0]+uvo[2][0]+uvo[0][0])/4;
4176
uv[1]=(2*uvo[3][1]+uvo[2][1]+uvo[0][1])/4;
4177
col1= cpack_fact(colo[1], colo[0], 0.25);
4178
col2= cpack_fact(colo[2], colo[3], 0.25);
4179
*col= cpack_fact(col1, col2, 0.25);
4181
else if (v==13) { /* case of test==9 */
4182
uv[0]=(2*uvo[0][0]+uvo[1][0]+uvo[3][0])/4;
4183
uv[1]=(2*uvo[0][1]+uvo[1][1]+uvo[3][1])/4;
4184
col1= cpack_fact(colo[1], colo[0], 0.25);
4185
col2= cpack_fact(colo[2], colo[3], 0.25);
4186
*col= cpack_fact(col1, col2, 0.75);
4188
/* default for consecutive verts*/
4190
uv_half(uv, uvo[v-5], uvo[v-4]);
4191
*col= cpack_fact(colo[v-5], colo[v-4], 0.5);
4196
for(a=0; a<3; a++, uv+=2, col++) {
4198
else if(a==1) v= v2;
4207
uv_half(uv, uvo[2], uvo[0]);
4208
*col= cpack_fact(colo[2], colo[0], 0.5);
4211
uv_half(uv, uvo[v-5], uvo[v-4]);
4212
*col= cpack_fact(colo[v-5], colo[v-4], 0.5);
4218
static EditVert *vert_from_number(EditVlak *evl, int nr)
4244
static void addvlak_subdiv(EditVlak *evl, int val1, int val2, int val3, int val4, EditVert *eve)
4247
EditVert *v1, *v2, *v3, *v4;
4249
if(val1>=9) v1= eve;
4250
else v1= vert_from_number(evl, val1);
4252
if(val2>=9) v2= eve;
4253
else v2= vert_from_number(evl, val2);
4255
if(val3>=9) v3= eve;
4256
else v3= vert_from_number(evl, val3);
4258
if(val4>=9) v4= eve;
4259
else v4= vert_from_number(evl, val4);
4261
w= addvlaklist(v1, v2, v3, v4, evl);
4263
if(evl->v4) set_wuv(4, w, val1, val2, val3, val4);
4264
else set_wuv(3, w, val1, val2, val3, val4);
4268
static float smoothperc= 0.0;
4270
static void smooth_subdiv_vec(float *v1, float *v2, float *n1, float *n2, float *vec)
4272
float len, fac, nor[3], nor1[3], nor2[3];
4274
VecSubf(nor, v1, v2);
4275
len= 0.5*Normalise(nor);
4281
fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
4283
vec[0]= fac*nor1[0];
4284
vec[1]= fac*nor1[1];
4285
vec[2]= fac*nor1[2];
4288
fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
4290
vec[0]+= fac*nor2[0];
4291
vec[1]+= fac*nor2[1];
4292
vec[2]+= fac*nor2[2];
4294
vec[0]*= smoothperc*len;
4295
vec[1]*= smoothperc*len;
4296
vec[2]*= smoothperc*len;
4299
static void smooth_subdiv_quad(EditVlak *evl, float *vec)
4302
float nor1[3], nor2[3];
4303
float vec1[3], vec2[3];
4306
/* vlr->e1->vn is new vertex inbetween v1 / v2 */
4308
VecMidf(nor1, evl->v1->no, evl->v2->no);
4310
VecMidf(nor2, evl->v3->no, evl->v4->no);
4313
smooth_subdiv_vec( evl->e1->vn->co, evl->e3->vn->co, nor1, nor2, vec1);
4315
VecMidf(nor1, evl->v2->no, evl->v3->no);
4317
VecMidf(nor2, evl->v4->no, evl->v1->no);
4320
smooth_subdiv_vec( evl->e2->vn->co, evl->e4->vn->co, nor1, nor2, vec2);
4322
VecAddf(vec1, vec1, vec2);
4324
CalcCent4f(cent, evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co);
4325
VecAddf(vec, cent, vec1);
4328
void subdivideflag(int flag, float rad, int beauty)
4330
EditMesh *em = G.editMesh;
4331
/* subdivide all with (vertflag & flag) */
4332
/* if rad>0.0 it's a 'sphere' subdivide */
4333
/* if rad<0.0 it's a fractal subdivide */
4334
extern float doublimit;
4336
EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
4338
float fac, vec[3], vec1[3], len1, len2, len3, percent;
4341
if(beauty & B_SMOOTH) {
4344
if(button(&perc, 10, 500, "Percentage:")==0) return;
4346
smoothperc= 0.292*perc/100.0;
4350
eed= em->edges.first;
4351
while((eed) && !(beauty & B_KNIFE)) {
4352
if( (eed->v1->f & flag) && (eed->v2->f & flag) ) eed->f= flag;
4357
/* if beauty: test for area and clear edge flags of 'ugly' edges */
4358
if(beauty & B_BEAUTY) {
4359
evl= em->faces.first;
4361
if( vlakselectedAND(evl, flag) ) {
4365
len1= AreaQ3Dfl(evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co);
4366
if(len1 <= doublimit) {
4373
len1= VecLenf(evl->v1->co, evl->v2->co) + VecLenf(evl->v3->co, evl->v4->co);
4374
len2= VecLenf(evl->v2->co, evl->v3->co) + VecLenf(evl->v1->co, evl->v4->co);
4380
else if(len1 > len2) {
4388
len1= AreaT3Dfl(evl->v1->co, evl->v2->co, evl->v3->co);
4389
if(len1 <= doublimit) {
4395
len1= VecLenf(evl->v1->co, evl->v2->co) ;
4396
len2= VecLenf(evl->v2->co, evl->v3->co) ;
4397
len3= VecLenf(evl->v3->co, evl->v1->co) ;
4399
if(len1<len2 && len1<len3) {
4402
else if(len2<len3 && len2<len1) {
4405
else if(len3<len2 && len3<len1) {
4415
if(beauty & B_SMOOTH) {
4417
vertexnormals(0); /* no1*/
4421
/* make new normal and put in edge, clear flag! needed for face creation part below */
4422
eed= em->edges.first;
4425
/* Subdivide percentage is stored in 1/32768ths in eed->f1 */
4426
if (beauty & B_PERCENTSUBD) percent=(float)(eed->f1)/32768.0;
4429
vec[0]= (1-percent)*eed->v1->co[0] + percent*eed->v2->co[0];
4430
vec[1]= (1-percent)*eed->v1->co[1] + percent*eed->v2->co[1];
4431
vec[2]= (1-percent)*eed->v1->co[2] + percent*eed->v2->co[2];
4433
if(rad > 0.0) { /* subdivide sphere */
4439
else if(rad< 0.0) { /* fractal subdivide */
4440
fac= rad* VecLenf(eed->v1->co, eed->v2->co);
4441
vec1[0]= fac*BLI_drand();
4442
vec1[1]= fac*BLI_drand();
4443
vec1[2]= fac*BLI_drand();
4444
VecAddf(vec, vec, vec1);
4447
if(beauty & B_SMOOTH) {
4448
smooth_subdiv_vec(eed->v1->co, eed->v2->co, eed->v1->no, eed->v2->no, vec1);
4449
VecAddf(vec, vec, vec1);
4452
eed->vn= addvertlist(vec);
4453
eed->vn->f= eed->v1->f;
4458
eed->f= 0; /* needed! */
4463
/* test all faces for subdivide edges, there are 8 or 16 cases (ugh)! */
4465
evl= em->faces.last;
4467
if( vlakselectedOR(evl, flag) ) {
4491
if(evl->v4==0) { /* All the permutations of 3 edges*/
4492
if((test & 3)==3) addvlak_subdiv(evl, 2, 2+4, 1+4, 0, 0);
4493
if((test & 6)==6) addvlak_subdiv(evl, 3, 3+4, 2+4, 0, 0);
4494
if((test & 5)==5) addvlak_subdiv(evl, 1, 1+4, 3+4, 0, 0);
4496
if(test==7) { /* four new faces, old face renews */
4500
set_wuv(3, evl, 1+4, 2+4, 3+4, 0);
4503
addvlak_subdiv(evl, 1+4, 2+4, 3, 0, 0);
4505
set_wuv(3, evl, 1, 1+4, 3, 0);
4508
addvlak_subdiv(evl, 2+4, 3+4, 1, 0, 0);
4510
set_wuv(3, evl, 1, 2, 2+4, 0);
4513
addvlak_subdiv(evl, 3+4, 1+4, 2, 0, 0);
4515
set_wuv(3, evl, 3+4, 2, 3, 0);
4518
addvlak_subdiv(evl, 1+4, 2, 3, 0, 0);
4520
set_wuv(3, evl, 1, 1+4, 3, 0);
4523
addvlak_subdiv(evl, 2+4, 3, 1, 0, 0);
4525
set_wuv(3, evl, 1, 2, 2+4, 0);
4528
addvlak_subdiv(evl, 3+4, 1, 2, 0, 0);
4530
set_wuv(3, evl, 3+4, 2, 3, 0);
4532
evl->e1= addedgelist(evl->v1, evl->v2);
4533
evl->e2= addedgelist(evl->v2, evl->v3);
4534
evl->e3= addedgelist(evl->v3, evl->v1);
4537
else { /* All the permutations of 4 faces */
4539
/* add a new point in center */
4540
CalcCent4f(vec, evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co);
4542
if(beauty & B_SMOOTH) {
4543
smooth_subdiv_quad(evl, vec); /* adds */
4545
eve= addvertlist(vec);
4549
addvlak_subdiv(evl, 2, 2+4, 9, 1+4, eve);
4550
addvlak_subdiv(evl, 3, 3+4, 9, 2+4, eve);
4551
addvlak_subdiv(evl, 4, 4+4, 9, 3+4, eve);
4556
set_wuv(4, evl, 1, 1+4, 9, 4+4);
4559
if(((test & 3)==3)&&(test!=3)) addvlak_subdiv(evl, 1+4, 2, 2+4, 0, 0);
4560
if(((test & 6)==6)&&(test!=6)) addvlak_subdiv(evl, 2+4, 3, 3+4, 0, 0);
4561
if(((test & 12)==12)&&(test!=12)) addvlak_subdiv(evl, 3+4, 4, 4+4, 0, 0);
4562
if(((test & 9)==9)&&(test!=9)) addvlak_subdiv(evl, 4+4, 1, 1+4, 0, 0);
4564
if(test==1) { /* Edge 1 has new vert */
4565
addvlak_subdiv(evl, 1+4, 2, 3, 0, 0);
4566
addvlak_subdiv(evl, 1+4, 3, 4, 0, 0);
4570
set_wuv(4, evl, 1, 1+4, 4, 0);
4572
else if(test==2) { /* Edge 2 has new vert */
4573
addvlak_subdiv(evl, 2+4, 3, 4, 0, 0);
4574
addvlak_subdiv(evl, 2+4, 4, 1, 0, 0);
4577
set_wuv(4, evl, 1, 2, 2+4, 0);
4579
else if(test==4) { /* Edge 3 has new vert */
4580
addvlak_subdiv(evl, 3+4, 4, 1, 0, 0);
4581
addvlak_subdiv(evl, 3+4, 1, 2, 0, 0);
4586
set_wuv(4, evl, 2, 3, 3+4, 0);
4588
else if(test==8) { /* Edge 4 has new vert */
4589
addvlak_subdiv(evl, 4+4, 1, 2, 0, 0);
4590
addvlak_subdiv(evl, 4+4, 2, 3, 0, 0);
4595
set_wuv(4, evl, 3, 4, 4+4, 0);
4597
else if(test==3) { /*edge 1&2 */
4598
/* make new vert in center of new edge */
4599
vec[0]=(e1->vn->co[0]+e2->vn->co[0])/2;
4600
vec[1]=(e1->vn->co[1]+e2->vn->co[1])/2;
4601
vec[2]=(e1->vn->co[2]+e2->vn->co[2])/2;
4602
eve= addvertlist(vec);
4605
addvlak_subdiv(evl, 4, 10, 2+4, 3, eve);
4606
addvlak_subdiv(evl, 4, 1, 1+4, 10, eve);
4607
/* orig face becomes small corner */
4613
set_wuv(4, evl, 1+4, 2, 2+4, 10);
4615
else if(test==6) { /* 2&3 */
4616
/* make new vert in center of new edge */
4617
vec[0]=(e2->vn->co[0]+e3->vn->co[0])/2;
4618
vec[1]=(e2->vn->co[1]+e3->vn->co[1])/2;
4619
vec[2]=(e2->vn->co[2]+e3->vn->co[2])/2;
4620
eve= addvertlist(vec);
4623
addvlak_subdiv(evl, 1, 11, 3+4, 4, eve);
4624
addvlak_subdiv(evl, 1, 2, 2+4, 11, eve);
4625
/* orig face becomes small corner */
4631
set_wuv(4, evl, 2+4, 3, 3+4, 11);
4633
else if(test==12) { /* 3&4 */
4634
/* make new vert in center of new edge */
4635
vec[0]=(e3->vn->co[0]+e4->vn->co[0])/2;
4636
vec[1]=(e3->vn->co[1]+e4->vn->co[1])/2;
4637
vec[2]=(e3->vn->co[2]+e4->vn->co[2])/2;
4638
eve= addvertlist(vec);
4641
addvlak_subdiv(evl, 2, 12, 4+4, 1, eve);
4642
addvlak_subdiv(evl, 2, 3, 3+4, 12, eve);
4643
/* orig face becomes small corner */
4649
set_wuv(4, evl, 3+4, 4, 4+4, 12);
4651
else if(test==9) { /* 4&1 */
4652
/* make new vert in center of new edge */
4653
vec[0]=(e1->vn->co[0]+e4->vn->co[0])/2;
4654
vec[1]=(e1->vn->co[1]+e4->vn->co[1])/2;
4655
vec[2]=(e1->vn->co[2]+e4->vn->co[2])/2;
4656
eve= addvertlist(vec);
4659
addvlak_subdiv(evl, 3, 13, 1+4, 2, eve);
4660
addvlak_subdiv(evl, 3, 4, 4+4, 13, eve);
4661
/* orig face becomes small corner */
4667
set_wuv(4, evl, 4+4, 1, 1+4, 13);
4669
else if(test==5) { /* 1&3 */
4670
addvlak_subdiv(evl, 1+4, 2, 3, 3+4, 0);
4673
set_wuv(4, evl, 1, 1+4, 3+4, 4);
4675
else if(test==10) { /* 2&4 */
4676
addvlak_subdiv(evl, 2+4, 3, 4, 4+4, 0);
4679
set_wuv(4, evl, 1, 2, 2+4, 4+4);
4680
}/* Unfortunately, there is no way to avoid tris on 1 or 3 edges*/
4681
else if(test==7) { /*1,2&3 */
4682
addvlak_subdiv(evl, 1+4, 2+4, 3+4, 0, 0);
4685
set_wuv(4, evl, 1, 1+4, 3+4, 4);
4688
else if(test==14) { /* 2,3&4 */
4689
addvlak_subdiv(evl, 2+4, 3+4, 4+4, 0, 0);
4692
set_wuv(4, evl, 1, 2, 2+4, 4+4);
4694
else if(test==13) {/* 1,3&4 */
4695
addvlak_subdiv(evl, 3+4, 4+4, 1+4, 0, 0);
4698
set_wuv(4, evl, 1+4, 3, 3, 3+4);
4700
else if(test==11) { /* 1,2,&4 */
4701
addvlak_subdiv(evl, 4+4, 1+4, 2+4, 0, 0);
4704
set_wuv(4, evl, 4+4, 2+4, 3, 4);
4707
evl->e1= addedgelist(evl->v1, evl->v2);
4708
evl->e2= addedgelist(evl->v2, evl->v3);
4709
if(evl->v4) evl->e3= addedgelist(evl->v3, evl->v4);
4710
else evl->e3= addedgelist(evl->v3, evl->v1);
4711
if(evl->v4) evl->e4= addedgelist(evl->v4, evl->v1);
4719
/* remove all old edges, if needed make new ones */
4720
eed= em->edges.first;
4725
if(eed->f==0) { /* not used in face */
4726
addedgelist(eed->v1,eed->vn);
4727
addedgelist(eed->vn,eed->v2);
4735
allqueue(REDRAWVIEW3D, 0);
4736
makeDispList(G.obedit);
4739
void adduplicateflag(int flag)
4741
EditMesh *em = G.editMesh;
4742
/* old verts have flag 128 set, and flag 'flag' cleared
4743
new verts have flag 'flag' set */
4744
EditVert *eve, *v1, *v2, *v3, *v4;
4748
/* vertices first */
4749
eve= em->verts.last;
4753
v1= addvertlist(eve->co);
4759
/* >>>>> FIXME: Copy deformation weight ? */
4760
v1->totweight = eve->totweight;
4761
if (eve->totweight){
4762
v1->dw = MEM_mallocN (eve->totweight * sizeof(MDeformWeight), "deformWeight");
4763
memcpy (v1->dw, eve->dw, eve->totweight * sizeof(MDeformWeight));
4771
eed= em->edges.first;
4773
if( (eed->v1->f & 128) && (eed->v2->f & 128) ) {
4781
/* then dupicate faces */
4782
evl= em->faces.first;
4784
if( (evl->v1->f & 128) && (evl->v2->f & 128) && (evl->v3->f & 128) ) {
4786
if(evl->v4->f & 128) {
4791
addvlaklist(v1, v2, v3, v4, evl);
4798
addvlaklist(v1, v2, v3, 0, evl);
4805
static void delvlakflag(int flag)
4807
EditMesh *em = G.editMesh;
4808
/* delete all faces with 'flag', including edges and loose vertices */
4809
/* in vertices the 'flag' is cleared */
4810
EditVert *eve,*nextve;
4811
EditEdge *eed, *nexted;
4812
EditVlak *evl,*nextvl;
4814
eed= em->edges.first;
4820
evl= em->faces.first;
4823
if(vlakselectedAND(evl, flag)) {
4832
BLI_remlink(&em->faces, evl);
4837
/* all faces with 1, 2 (3) vertices selected: make sure we keep the edges */
4838
evl= em->faces.first;
4850
/* test all edges for vertices with 'flag', and clear */
4851
eed= em->edges.first;
4858
else if( (eed->v1->f & flag) || (eed->v2->f & flag) ) {
4864
/* vertices with 'flag' now are the loose ones, and will be removed */
4865
eve= em->verts.first;
4869
BLI_remlink(&em->verts, eve);
4877
void extrude_mesh(void)
4883
if(okee("Extrude")==0) return;
4886
undo_push_mesh("Extrude");
4888
a= extrudeflag(1,1);
4891
error("No valid vertices selected");
4894
countall(); /* for G.totvert in calc_meshverts() */
4901
void adduplicate_mesh(void)
4907
undo_push_mesh("Duplicate");
4910
countall(); /* for G.totvert in calc_meshverts() */
4914
void split_mesh(void)
4919
if(okee(" Split ")==0) return;
4922
undo_push_mesh("Split");
4923
/* make duplicate first */
4925
/* old faces have 3x flag 128 set, delete them */
4931
allqueue(REDRAWVIEW3D, 0);
4932
makeDispList(G.obedit);
1283
BIF_undo_push("Undo all changes");
1286
/* *************** SEPARATE (partial exit editmode) *************/
4936
1289
void separatemenu(void)
4940
event = pupmenu("Separate (No undo!) %t|Selected%x1|All loose parts%x2");
1293
if(G.editMesh->verts.first==NULL) return;
1295
event = pupmenu("Separate (No undo!) %t|Selected%x1|All Loose Parts%x2");
4942
1297
if (event==0) return;
4945
1300
switch (event) {
4951
separate_mesh_loose();
1305
separate_mesh_loose();
5278
1605
/* unselect the vertices that we (ab)used for the separation*/
5279
eve= em->verts.first;
1606
EM_clear_flag_all(SELECT);
5287
1610
allqueue(REDRAWVIEW3D, 0);
5288
1611
makeDispList(G.obedit);
5292
void extrude_repeat_mesh(int steps, float offs)
5294
float dvec[3], tmat[3][3], bmat[3][3];
5300
undo_push_mesh("Extrude Repeat");
5303
dvec[0]= G.vd->persinv[2][0];
5304
dvec[1]= G.vd->persinv[2][1];
5305
dvec[2]= G.vd->persinv[2][2];
5311
/* base correction */
5312
Mat3CpyMat4(bmat, G.obedit->obmat);
5313
Mat3Inv(tmat, bmat);
5314
Mat3MulVecfl(tmat, dvec);
5316
for(a=0;a<steps;a++) {
5317
ok= extrudeflag(1,1);
5319
error("No valid vertices selected");
5322
translateflag(1, dvec);
5326
allqueue(REDRAWVIEW3D, 0);
5327
makeDispList(G.obedit);
5331
void spin_mesh(int steps,int degr,float *dvec, int mode)
5333
EditMesh *em = G.editMesh;
5334
EditVert *eve,*nextve;
5335
float *curs, si,n[3],q[4],cmat[3][3],imat[3][3], tmat[3][3];
5336
float cent[3],bmat[3][3];
5344
undo_push_mesh("Spin");
5346
/* imat and centre and size */
5347
Mat3CpyMat4(bmat, G.obedit->obmat);
5350
curs= give_cursor();
5351
VECCOPY(cent, curs);
5352
cent[0]-= G.obedit->obmat[3][0];
5353
cent[1]-= G.obedit->obmat[3][1];
5354
cent[2]-= G.obedit->obmat[3][2];
5355
Mat3MulVecfl(imat, cent);
5357
phi= degr*M_PI/360.0;
5359
if(editbutflag & B_CLOCKWISE) phi= -phi;
5365
n[0]= G.vd->viewinv[2][0];
5366
n[1]= G.vd->viewinv[2][1];
5367
n[2]= G.vd->viewinv[2][2];
5376
QuatToMat3(q, cmat);
5378
Mat3MulMat3(tmat,cmat,bmat);
5379
Mat3MulMat3(bmat,imat,tmat);
5381
if(mode==0) if(editbutflag & B_KEEPORIG) adduplicateflag(1);
5384
for(a=0;a<steps;a++) {
5385
if(mode==0) ok= extrudeflag(1,1);
5386
else adduplicateflag(1);
5388
error("No valid vertices selected");
5391
rotateflag(1, cent, bmat);
5393
Mat3MulVecfl(bmat,dvec);
5394
translateflag(1,dvec);
5400
/* no vertices or only loose ones selected, remove duplicates */
5401
eve= em->verts.first;
5405
BLI_remlink(&em->verts,eve);
5412
recalc_editnormals();
5413
allqueue(REDRAWVIEW3D, 0);
5414
makeDispList(G.obedit);
5417
void screw_mesh(int steps,int turns)
5419
EditMesh *em = G.editMesh;
5420
EditVert *eve,*v1=0,*v2=0;
5422
float dvec[3], nor[3];
5426
/* first condition: we need frontview! */
5428
error("Only in frontview!");
5432
undo_push_mesh("Screw");
5435
eve= em->verts.first;
5440
/* edges set flags in verts */
5441
eed= em->edges.first;
5443
if(eed->v1->f & 1) {
5444
if(eed->v2->f & 1) {
5445
/* watch: f1 is a byte */
5446
if(eed->v1->f1<2) eed->v1->f1++;
5447
if(eed->v2->f1<2) eed->v2->f1++;
5452
/* find two vertices with eve->f1==1, more or less is wrong */
5453
eve= em->verts.first;
5457
else if(v2==0) v2= eve;
5465
if(v1==0 || v2==0) {
5466
error("No curve selected");
5470
/* calculate dvec */
5471
dvec[0]= ( (v1->co[0]- v2->co[0]) )/(steps);
5472
dvec[1]= ( (v1->co[1]- v2->co[1]) )/(steps);
5473
dvec[2]= ( (v1->co[2]- v2->co[2]) )/(steps);
5475
VECCOPY(nor, G.obedit->obmat[2]);
5477
if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) {
5483
spin_mesh(turns*steps, turns*360, dvec, 0);
5487
void selectswap_mesh(void)
5489
EditMesh *em = G.editMesh;
5492
eve= em->verts.first;
5495
if(eve->f & 1) eve->f&= ~1;
5501
allqueue(REDRAWVIEW3D, 0);
5505
/* ******************************* ADD ********************* */
5507
void addvert_mesh(void)
5509
EditMesh *em = G.editMesh;
5510
EditVert *eve,*v1=0;
5511
float *curs, mat[3][3],imat[3][3];
5515
Mat3CpyMat4(mat, G.obedit->obmat);
5518
v1= em->verts.first;
5520
if(v1->f & 1) break;
5523
eve= v1; /* prevent there are more selected */
5529
eve= addvertlist(0);
5531
curs= give_cursor();
5532
VECCOPY(eve->co, curs);
5535
VecSubf(eve->co, eve->co, G.obedit->obmat[3]);
5537
Mat3MulVecfl(imat, eve->co);
5541
addedgelist(v1, eve);
5545
allqueue(REDRAWVIEW3D, 0);
5546
makeDispList(G.obedit);
5548
while(get_mbut()&R_MOUSE);
5552
void addedgevlak_mesh(void)
5554
EditMesh *em = G.editMesh;
5555
EditVert *eve, *neweve[4];
5557
float con1, con2, con3;
5560
if( (G.vd->lay & G.obedit->lay)==0 ) return;
5562
/* how many selected ? */
5563
eve= em->verts.first;
5568
neweve[aantal-1]= eve;
5573
addedgelist(neweve[0], neweve[1]);
5574
allqueue(REDRAWVIEW3D, 0);
5575
makeDispList(G.obedit);
5578
if(aantal<2 || aantal>4) {
5579
error("Can't make edge/face");
5583
evl= NULL; // check later
5586
if(exist_vlak(neweve[0], neweve[1], neweve[2], 0)==0) {
5588
evl= addvlaklist(neweve[0], neweve[1], neweve[2], 0, NULL);
5591
else error("Already a face");
5593
else if(aantal==4) {
5594
if(exist_vlak(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
5596
con1= convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co);
5597
con2= convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co);
5598
con3= convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co);
5600
if(con1>=con2 && con1>=con3)
5601
evl= addvlaklist(neweve[0], neweve[1], neweve[2], neweve[3], NULL);
5602
else if(con2>=con1 && con2>=con3)
5603
evl= addvlaklist(neweve[0], neweve[2], neweve[3], neweve[1], NULL);
5605
evl= addvlaklist(neweve[0], neweve[2], neweve[1], neweve[3], NULL);
5608
else error("Already a face");
5611
if(evl) { // now we're calculating direction of normal
5613
/* dot product view mat with normal, should give info! */
5615
CalcNormFloat(evl->v1->co, evl->v2->co, evl->v3->co, evl->n);
5617
inp= evl->n[0]*G.vd->viewmat[0][2] + evl->n[1]*G.vd->viewmat[1][2] + evl->n[2]*G.vd->viewmat[2][2];
5619
if(inp < 0.0) flipvlak(evl);
5623
allqueue(REDRAWVIEW3D, 0);
5624
makeDispList(G.obedit);
5627
static void erase_edges(ListBase *l)
5629
EditEdge *ed, *nexted;
5631
ed = (EditEdge *) l->first;
5634
if( (ed->v1->f & 1) || (ed->v2->f & 1) ) {
5642
static void erase_faces(ListBase *l)
5644
EditVlak *f, *nextf;
5646
f = (EditVlak *) l->first;
5650
if( vlakselectedOR(f, 1) ) {
5658
static void erase_vertices(ListBase *l)
5660
EditVert *v, *nextv;
5662
v = (EditVert *) l->first;
5673
void delete_mesh(void)
5675
EditMesh *em = G.editMesh;
5676
EditVlak *evl, *nextvl;
5677
EditVert *eve,*nextve;
5678
EditEdge *eed,*nexted;
5684
event= pupmenu("ERASE %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5");
5688
undo_push_mesh("Erase Vertices");
5689
erase_edges(&em->edges);
5690
erase_faces(&em->faces);
5691
erase_vertices(&em->verts);
5694
undo_push_mesh("Erase Edges & Faces");
5695
evl= em->faces.first;
5698
/* delete only faces with 2 or more vertices selected */
5700
if(evl->v1->f & 1) count++;
5701
if(evl->v2->f & 1) count++;
5702
if(evl->v3->f & 1) count++;
5703
if(evl->v4 && (evl->v4->f & 1)) count++;
5705
BLI_remlink(&em->faces, evl);
5710
eed= em->edges.first;
5713
if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
5719
evl= em->faces.first;
5723
if( evl->v1->f & 1) event++;
5724
if( evl->v2->f & 1) event++;
5725
if( evl->v3->f & 1) event++;
5726
if(evl->v4 && (evl->v4->f & 1)) event++;
5729
BLI_remlink(&em->faces, evl);
5736
undo_push_mesh("Erase Edges");
5737
eed= em->edges.first;
5740
if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
5746
evl= em->faces.first;
5750
if( evl->v1->f & 1) event++;
5751
if( evl->v2->f & 1) event++;
5752
if( evl->v3->f & 1) event++;
5753
if(evl->v4 && (evl->v4->f & 1)) event++;
5756
BLI_remlink(&em->faces, evl);
5761
/* to remove loose vertices: */
5762
eed= em->edges.first;
5764
if( eed->v1->f & 1) eed->v1->f-=1;
5765
if( eed->v2->f & 1) eed->v2->f-=1;
5768
eve= em->verts.first;
5772
BLI_remlink(&em->verts,eve);
5780
undo_push_mesh("Erase Faces");
5784
undo_push_mesh("Erase All");
5785
if(em->verts.first) free_vertlist(&em->verts);
5786
if(em->edges.first) free_edgelist(&em->edges);
5787
if(em->faces.first) free_vlaklist(&em->faces);
5790
undo_push_mesh("Erase Only Faces");
5791
evl= em->faces.first;
5794
if(vlakselectedAND(evl, 1)) {
5795
BLI_remlink(&em->faces, evl);
5803
allqueue(REDRAWVIEW3D, 0);
5804
makeDispList(G.obedit);
5809
void add_primitiveMesh(int type)
5811
EditMesh *em = G.editMesh;
5813
EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
5814
float *curs, d, dia, phi, phid, cent[3], vec[3], imat[3][3], mat[3][3];
5815
float q[4], cmat[3][3];
5816
static short tot=32, seg=32, subdiv=2;
5817
short a, b, ext=0, fill=0, totoud, newob=0;
5819
if(G.scene->id.lib) return;
5821
/* this function also comes from an info window */
5822
if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
5825
check_editmode(OB_MESH);
5827
G.f &= ~(G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT);
5828
setcursor_space(SPACE_VIEW3D, CURSOR_STD);
5830
/* if no obedit: new object and enter editmode */
5832
/* add_object actually returns an object ! :-)
5833
But it also stores the added object struct in
5834
G.scene->basact->object (BASACT->object) */
5836
add_object_draw(OB_MESH);
5838
G.obedit= BASACT->object;
5840
where_is_object(G.obedit);
5843
setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
5849
eve= em->verts.first;
5851
if(eve->f & 1) eve->f&= ~1;
5855
totoud= tot; /* store, and restore when cube/plane */
5857
/* imat and centre and size */
5858
Mat3CpyMat4(mat, G.obedit->obmat);
5860
curs= give_cursor();
5861
VECCOPY(cent, curs);
5862
cent[0]-= G.obedit->obmat[3][0];
5863
cent[1]-= G.obedit->obmat[3][1];
5864
cent[2]-= G.obedit->obmat[3][2];
5867
Mat3CpyMat4(imat, G.vd->viewmat);
5868
Mat3MulVecfl(imat, cent);
5869
Mat3MulMat3(cmat, imat, mat);
5875
/* ext==extrudeflag, tot==amount of vertices in basis */
5882
if(newob) rename_id((ID *)G.obedit, "Plane");
5883
if(newob) rename_id((ID *)me, "Plane");
5889
if(newob) rename_id((ID *)G.obedit, "Cube");
5890
if(newob) rename_id((ID *)me, "Cube");
5892
case 4: /* circle */
5893
if(button(&tot,3,100,"Vertices:")==0) return;
5896
if(newob) rename_id((ID *)G.obedit, "Circle");
5897
if(newob) rename_id((ID *)me, "Circle");
5899
case 5: /* cylinder */
5900
if(button(&tot,3,100,"Vertices:")==0) return;
5903
if(newob) rename_id((ID *)G.obedit, "Cylinder");
5904
if(newob) rename_id((ID *)me, "Cylinder");
5907
if(button(&tot,3,100,"Vertices:")==0) return;
5910
if(newob) rename_id((ID *)G.obedit, "Tube");
5911
if(newob) rename_id((ID *)me, "Tube");
5914
if(button(&tot,3,100,"Vertices:")==0) return;
5917
if(newob) rename_id((ID *)G.obedit, "Cone");
5918
if(newob) rename_id((ID *)me, "Cone");
5921
if(button(&tot,2,100,"X res:")==0) return;
5922
if(button(&seg,2,100,"Y res:")==0) return;
5923
if(newob) rename_id((ID *)G.obedit, "Grid");
5924
if(newob) rename_id((ID *)me, "Grid");
5926
case 11: /* UVsphere */
5927
if(button(&seg,3,100,"Segments:")==0) return;
5928
if(button(&tot,3,100,"Rings:")==0) return;
5929
if(newob) rename_id((ID *)G.obedit, "Sphere");
5930
if(newob) rename_id((ID *)me, "Sphere");
5932
case 12: /* Icosphere */
5933
if(button(&subdiv,1,5,"Subdivision:")==0) return;
5934
if(newob) rename_id((ID *)G.obedit, "Sphere");
5935
if(newob) rename_id((ID *)me, "Sphere");
5937
case 13: /* Monkey */
5938
if(newob) rename_id((ID *)G.obedit, "Suzanne");
5939
if(newob) rename_id((ID *)me, "Suzanne");
5943
dia= sqrt(2.0)*G.vd->grid;
5949
if(type<10) { /* all types except grid, sphere... */
5950
if(ext==0 && type!=7) d= 0;
5953
vtop= vdown= v1= v2= 0;
5954
for(b=0; b<=ext; b++) {
5955
for(a=0; a<tot; a++) {
5957
vec[0]= cent[0]+dia*sin(phi);
5958
vec[1]= cent[1]+dia*cos(phi);
5961
Mat3MulVecfl(imat, vec);
5962
eve= addvertlist(vec);
5972
/* centre vertices */
5973
if(fill && type>1) {
5976
Mat3MulVecfl(imat,vec);
5977
vdown= addvertlist(vec);
5978
if(ext || type==7) {
5981
Mat3MulVecfl(imat,vec);
5982
vtop= addvertlist(vec);
5988
if(vtop) vtop->f= 1;
5989
if(vdown) vdown->f= 1;
5991
/* top and bottom face */
5993
if(tot==4 && (type==0 || type==1)) {
5995
if(ext) v4= v2->next->next;
5997
addvlaklist(v3, v1->next, v1, v3->next, NULL);
5998
if(ext) addvlaklist(v2, v2->next, v4, v4->next, NULL);
6004
for(a=1; a<tot; a++) {
6005
addvlaklist(vdown, v3, v3->next, 0, NULL);
6008
addvlaklist(vtop, v4, v4->next, 0, NULL);
6013
addvlaklist(vdown, v3, v1, 0, NULL);
6014
if(ext) addvlaklist(vtop, v4, v2, 0, NULL);
6018
else if(type==4) { /* we need edges for a circle */
6020
for(a=1;a<tot;a++) {
6021
addedgelist(v3,v3->next);
6030
for(a=1; a<tot; a++) {
6031
addvlaklist(v3, v3->next, v4->next, v4, NULL);
6035
addvlaklist(v3, v1, v2, v4, NULL);
6037
else if(type==7) { /* cone */
6039
for(a=1; a<tot; a++) {
6040
addvlaklist(vtop, v3->next, v3, 0, NULL);
6043
addvlaklist(vtop, v1, v3, 0, NULL);
6046
if(type<2) tot= totoud;
6049
else if(type==10) { /* grid */
6051
eve= em->verts.first;
6057
/* one segment first: de X as */
6059
phid= 2.0/((float)tot-1);
6060
for(a=0;a<tot;a++) {
6061
vec[0]= cent[0]+dia*phi;
6062
vec[1]= cent[1]- dia;
6064
Mat3MulVecfl(imat,vec);
6065
eve= addvertlist(vec);
6067
if (a) addedgelist(eve->prev,eve);
6070
/* extrude and translate */
6071
vec[0]= vec[2]= 0.0;
6073
Mat3MulVecfl(imat, vec);
6074
for(a=0;a<seg-1;a++) {
6076
translateflag(2, vec);
6079
else if(type==11) { /* UVsphere */
6082
/* clear all flags */
6083
eve= em->verts.first;
6089
/* one segment first */
6092
for(a=0; a<=tot; a++) {
6093
vec[0]= cent[0]+dia*sin(phi);
6095
vec[2]= cent[2]+dia*cos(phi);
6096
Mat3MulVecfl(imat,vec);
6097
eve= addvertlist(vec);
6100
else addedgelist(eve->prev, eve);
6104
/* extrude and rotate */
6109
QuatToMat3(q, cmat);
6110
Mat3MulMat3(tmat, cmat, mat);
6111
Mat3MulMat3(cmat, imat, tmat);
6113
for(a=0; a<seg; a++) {
6115
rotateflag(2, v1->co, cmat);
6117
removedoublesflag(4, 0.01);
6119
else if(type==12) { /* Icosphere */
6122
/* clear all flags */
6123
eve= em->verts.first;
6130
vec[0]= dia*icovert[a][0];
6131
vec[1]= dia*icovert[a][1];
6132
vec[2]= dia*icovert[a][2];
6133
eva[a]= addvertlist(vec);
6137
v1= eva[ icovlak[a][0] ];
6138
v2= eva[ icovlak[a][1] ];
6139
v3= eva[ icovlak[a][2] ];
6140
addvlaklist(v1, v2, v3, 0, NULL);
6144
for(a=1; a<subdiv; a++) subdivideflag(2, dia, 0);
6145
/* and now do imat */
6146
eve= em->verts.first;
6149
VecAddf(eve->co,eve->co,cent);
6150
Mat3MulVecfl(imat,eve->co);
6154
} else if (type==13) { /* Monkey */
6155
extern int monkeyo, monkeynv, monkeynf;
6156
extern signed char monkeyf[][4];
6157
extern signed char monkeyv[][3];
6158
EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv");
6161
for (i=0; i<monkeynv; i++) {
6163
v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0;
6164
tv[i]= addvertlist(v);
6165
tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(v);
6167
for (i=0; i<monkeynf; i++) {
6168
addvlaklist(tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL);
6169
addvlaklist(tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL);
6175
if(type!=0 && type!=10) righthandfaces(1);
6178
allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
6179
allqueue(REDRAWALL, 0);
6180
makeDispList(G.obedit);
6182
if (type==13) notice("Oooh Oooh Oooh");
6185
void vertexsmooth(void)
6187
EditMesh *em = G.editMesh;
6190
float *adror, *adr, fac;
6194
if(G.obedit==0) return;
6197
eve= em->verts.first;
6199
if(eve->f & 1) teller++;
6202
if(teller==0) return;
6204
undo_push_mesh("Smooth");
6206
adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
6207
eve= em->verts.first;
6210
eve->vn= (EditVert *)adr;
6217
eed= em->edges.first;
6219
if( (eed->v1->f & 1) || (eed->v2->f & 1) ) {
6220
fvec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0;
6221
fvec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0;
6222
fvec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0;
6224
if((eed->v1->f & 1) && eed->v1->f1<255) {
6226
VecAddf((float *)eed->v1->vn, (float *)eed->v1->vn, fvec);
6228
if((eed->v2->f & 1) && eed->v2->f1<255) {
6230
VecAddf((float *)eed->v2->vn, (float *)eed->v2->vn, fvec);
6236
eve= em->verts.first;
6240
adr= (float *)eve->vn;
6241
fac= 0.5/(float)eve->f1;
6243
eve->co[0]= 0.5*eve->co[0]+fac*adr[0];
6244
eve->co[1]= 0.5*eve->co[1]+fac*adr[1];
6245
eve->co[2]= 0.5*eve->co[2]+fac*adr[2];
6253
allqueue(REDRAWVIEW3D, 0);
6254
makeDispList(G.obedit);
6257
void vertexnoise(void)
6259
EditMesh *em = G.editMesh;
6264
float b2, ofs, vec[3];
6266
if(G.obedit==0) return;
6268
undo_push_mesh("Noise");
6270
ma= give_current_material(G.obedit, G.obedit->actcol);
6271
if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
6274
tex= ma->mtex[0]->tex;
6276
ofs= tex->turbul/200.0;
6278
eve= (struct EditVert *)em->verts.first;
6282
if(tex->type==TEX_STUCCI) {
6284
b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
6285
if(tex->stype) ofs*=(b2*b2);
6286
vec[0]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
6287
vec[1]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
6288
vec[2]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
6290
VecAddf(eve->co, eve->co, vec);
6294
externtex(ma->mtex[0], eve->co);
6296
eve->co[2]+= 0.05*Tin;
6302
allqueue(REDRAWVIEW3D, 0);
6303
makeDispList(G.obedit);
6306
void hide_mesh(int swap)
6308
EditMesh *em = G.editMesh;
6312
if(G.obedit==0) return;
6315
eve= em->verts.first;
6317
if((eve->f & 1)==0) {
6325
eve= em->verts.first;
6335
eed= em->edges.first;
6337
if(eed->v1->h || eed->v2->h) eed->h= 1;
6342
allqueue(REDRAWVIEW3D, 0);
6343
makeDispList(G.obedit);
6347
void reveal_mesh(void)
6349
EditMesh *em = G.editMesh;
6353
if(G.obedit==0) return;
6355
eve= em->verts.first;
6364
eed= em->edges.first;
6370
allqueue(REDRAWVIEW3D, 0);
6371
makeDispList(G.obedit);
6374
static float convex(float *v1, float *v2, float *v3, float *v4)
6376
float cross[3], test[3];
6379
CalcNormFloat(v1, v2, v3, cross);
6380
CalcNormFloat(v1, v3, v4, test);
6382
inpr= cross[0]*test[0]+cross[1]*test[1]+cross[2]*test[2];
6387
/* returns vertices of two adjacent triangles forming a quad
6388
- can be righthand or lefthand
6399
#define VTEST(face, num, other) \
6400
(face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3)
6402
static void givequadverts(EditVlak *evl, EditVlak *evl1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, float **uv, unsigned int *col)
6404
if VTEST(evl, 1, evl1) {
6405
//if(evl->v1!=evl1->v1 && evl->v1!=evl1->v2 && evl->v1!=evl1->v3) {
6408
uv[0] = evl->tf.uv[0];
6409
uv[1] = evl->tf.uv[1];
6410
col[0] = evl->tf.col[0];
6411
col[1] = evl->tf.col[1];
6413
else if VTEST(evl, 2, evl1) {
6414
//else if(evl->v2!=evl1->v1 && evl->v2!=evl1->v2 && evl->v2!=evl1->v3) {
6417
uv[0] = evl->tf.uv[1];
6418
uv[1] = evl->tf.uv[2];
6419
col[0] = evl->tf.col[1];
6420
col[1] = evl->tf.col[2];
6422
else if VTEST(evl, 3, evl1) {
6423
// else if(evl->v3!=evl1->v1 && evl->v3!=evl1->v2 && evl->v3!=evl1->v3) {
6426
uv[0] = evl->tf.uv[2];
6427
uv[1] = evl->tf.uv[0];
6428
col[0] = evl->tf.col[2];
6429
col[1] = evl->tf.col[0];
6432
if VTEST(evl1, 1, evl) {
6433
// if(evl1->v1!=evl->v1 && evl1->v1!=evl->v2 && evl1->v1!=evl->v3) {
6435
uv[2] = evl1->tf.uv[0];
6436
col[2] = evl1->tf.col[0];
6439
uv[3] = evl1->tf.uv[1];
6440
col[3] = evl1->tf.col[1];
6442
if(evl1->v2== *v2) {
6444
uv[3] = evl1->tf.uv[2];
6447
uv[3] = evl1->tf.uv[1];
6451
else if VTEST(evl1, 2, evl) {
6452
// else if(evl1->v2!=evl->v1 && evl1->v2!=evl->v2 && evl1->v2!=evl->v3) {
6454
uv[2] = evl1->tf.uv[1];
6455
col[2] = evl1->tf.col[1];
6458
uv[3] = evl1->tf.uv[2];
6459
col[3] = evl1->tf.col[2];
6461
if(evl1->v3== *v2) {
6463
uv[3] = evl1->tf.uv[0];
6466
uv[3] = evl1->tf.uv[2];
6470
else if VTEST(evl1, 3, evl) {
6471
// else if(evl1->v3!=evl->v1 && evl1->v3!=evl->v2 && evl1->v3!=evl->v3) {
6473
uv[2] = evl1->tf.uv[2];
6474
col[2] = evl1->tf.col[2];
6477
uv[3] = evl1->tf.uv[0];
6478
col[3] = evl1->tf.col[0];
6480
if(evl1->v1== *v2) {
6482
uv[3] = evl1->tf.uv[3];
6485
uv[3] = evl1->tf.uv[0];
6490
pupmenu("Wanna crash?%t|Yes Please!%x1");
6498
/* Helper functions for edge/quad edit features*/
6500
static void untag_edges(EditVlak *f)
6504
if (f->e3) f->e3->f = 0;
6505
if (f->e4) f->e4->f = 0;
6509
static void mark_clear_edges(EditVlak *f)
6513
if (f->e3) f->e3->f1 = 1;
6514
if (f->e4) f->e4->f1 = 1;
6518
static int count_edges(EditEdge *ed)
6523
if( (ed->v1->f & 1) && (ed->v2->f & 1) ) totedge++;
6529
/** remove and free list of tagged edges */
6530
static void free_tagged_edgelist(EditEdge *eed)
6543
/** remove and free list of tagged faces */
6545
static void free_tagged_facelist(EditVlak *evl)
6547
EditMesh *em = G.editMesh;
6553
BLI_remlink(&em->faces, evl);
6560
typedef EditVlak *EVPtr;
6561
typedef EVPtr EVPTuple[2];
6563
/** builds EVPTuple array evla of face tuples (in fact pointers to EditVlaks)
6565
arguments: selected edge list, face list.
6566
Edges will also be tagged accordingly (see eed->f) */
6568
static int collect_quadedges(EVPTuple *evla, EditEdge *eed, EditVlak *evl)
6571
EditEdge *e1, *e2, *e3;
6574
/* run through edges, if selected, set pointer edge-> facearray */
6578
if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
6579
eed->vn= (EditVert *) (&evla[i]);
6586
/* find edges pointing to 2 faces by procedure:
6588
- run through faces and their edges, increase
6589
face counter e->f for each face
6594
if(evl->v4==0) { /* if triangle */
6595
if(vlakselectedAND(evl, 1)) {
6602
evp= (EVPtr *) e1->vn;
6603
evp[(int)e1->f]= evl;
6609
evp= (EVPtr *) e2->vn;
6610
evp[(int)e2->f]= evl;
6616
evp= (EVPtr *) e3->vn;
6617
evp[(int)e3->f]= evl;
6629
void join_triangles(void)
6631
EditMesh *em = G.editMesh;
6632
EditVert *v1, *v2, *v3, *v4;
6636
EditEdge *eed, *nexted;
6639
unsigned int col[4];
6642
totedge = count_edges(em->edges.first);
6643
if(totedge==0) return;
6645
undo_push_mesh("Join triangles");
6647
evlar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "jointris");
6649
ok = collect_quadedges(evlar, em->edges.first, em->faces.first);
6650
if (G.f & G_DEBUG) {
6651
printf("edges selected: %d\n", ok);
6654
eed= em->edges.first;
6658
if(eed->f==2) { /* points to 2 faces */
6660
evla= (EVPtr *) eed->vn;
6662
/* don't do it if flagged */
6666
if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0;
6668
if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0;
6672
givequadverts(evla[0], evla[1], &v1, &v2, &v3, &v4, uv, col);
6683
/* make new faces */
6684
if( convex(v1->co, v2->co, v3->co, v4->co) > 0.01) {
6685
if(exist_vlak(v1, v2, v3, v4)==0) {
6686
w = addvlaklist(v1, v2, v3, v4, evla[0]);
6689
UVCOPY(w->tf.uv[0], uv[0]);
6690
UVCOPY(w->tf.uv[1], uv[1]);
6691
UVCOPY(w->tf.uv[2], uv[2]);
6692
UVCOPY(w->tf.uv[3], uv[3]);
6694
memcpy(w->tf.col, col, sizeof(w->tf.col));
6696
/* tag as to-be-removed */
6697
FACE_MARKCLEAR(evla[0]);
6698
FACE_MARKCLEAR(evla[1]);
6700
} /* endif test convex */
6705
free_tagged_edgelist(em->edges.first);
6706
free_tagged_facelist(em->faces.first);
6710
allqueue(REDRAWVIEW3D, 0);
6711
makeDispList(G.obedit);
6715
/* quick hack, basically a copy of beauty_fill */
6716
void edge_flip(void)
6718
EditMesh *em = G.editMesh;
6719
EditVert *v1, *v2, *v3, *v4;
6720
EditEdge *eed, *nexted;
6722
//void **evlar, **evla;
6727
unsigned int col[4];
6731
/* - all selected edges with two faces
6732
* - find the faces: store them in edges (using datablock)
6733
* - per edge: - test convex
6734
* - test edge: flip?
6735
- if true: remedge, addedge, all edges at the edge get new face pointers
6738
totedge = count_edges(em->edges.first);
6739
if(totedge==0) return;
6741
undo_push_mesh("Flip edges");
6743
/* temporary array for : edge -> face[1], face[2] */
6744
evlar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip");
6746
ok = collect_quadedges(evlar, em->edges.first, em->faces.first);
6748
eed= em->edges.first;
6752
if(eed->f==2) { /* points to 2 faces */
6754
evla= (EVPtr *) eed->vn;
6756
/* don't do it if flagged */
6760
if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0;
6762
if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0;
6766
givequadverts(evla[0], evla[1], &v1, &v2, &v3, &v4, uv, col);
6777
/* make new faces */
6778
if (v1 && v2 && v3){
6779
if( convex(v1->co, v2->co, v3->co, v4->co) > 0.01) {
6780
if(exist_vlak(v1, v2, v3, v4)==0) {
6781
w = addvlaklist(v1, v2, v3, 0, evla[1]);
6785
UVCOPY(w->tf.uv[0], uv[0]);
6786
UVCOPY(w->tf.uv[1], uv[1]);
6787
UVCOPY(w->tf.uv[2], uv[2]);
6789
w->tf.col[0] = col[0]; w->tf.col[1] = col[1]; w->tf.col[2] = col[2];
6791
w = addvlaklist(v1, v3, v4, 0, evla[1]);
6794
UVCOPY(w->tf.uv[0], uv[0]);
6795
UVCOPY(w->tf.uv[1], uv[2]);
6796
UVCOPY(w->tf.uv[2], uv[3]);
6798
w->tf.col[0] = col[0]; w->tf.col[1] = col[2]; w->tf.col[2] = col[3];
6800
/* erase old faces and edge */
6802
/* tag as to-be-removed */
6803
FACE_MARKCLEAR(evla[1]);
6804
FACE_MARKCLEAR(evla[0]);
6807
} /* endif test convex */
6814
/* clear tagged edges and faces: */
6815
free_tagged_edgelist(em->edges.first);
6816
free_tagged_facelist(em->faces.first);
6820
allqueue(REDRAWVIEW3D, 0);
6821
makeDispList(G.obedit);
6824
void beauty_fill(void)
6826
EditMesh *em = G.editMesh;
6827
EditVert *v1, *v2, *v3, *v4;
6828
EditEdge *eed, *nexted;
6829
EditEdge dia1, dia2;
6831
// void **evlar, **evla;
6835
unsigned int col[4];
6836
float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
6837
int totedge, ok, notbeauty=8, onedone;
6839
/* - all selected edges with two faces
6840
* - find the faces: store them in edges (using datablock)
6841
* - per edge: - test convex
6842
* - test edge: flip?
6843
* - if true: remedge, addedge, all edges at the edge get new face pointers
6846
totedge = count_edges(em->edges.first);
6847
if(totedge==0) return;
6849
if(okee("Beauty Fill")==0) return;
6851
undo_push_mesh("Beauty Fill");
6853
/* temp block with face pointers */
6854
evlar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill");
6859
ok = collect_quadedges(evlar, em->edges.first, em->faces.first);
6864
eed= em->edges.first;
6870
evla = (EVPtr *) eed->vn;
6872
/* none of the faces should be treated before */
6875
if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0;
6877
if(evl->e1->f1 || evl->e2->f1 || evl->e3->f1) ok= 0;
6881
givequadverts(evla[0], evla[1], &v1, &v2, &v3, &v4, uv, col);
6882
if( convex(v1->co, v2->co, v3->co, v4->co) > -0.5) {
6885
if( ((long)v1) > ((long)v3) ) {
6894
if( ((long)v2) > ((long)v4) ) {
6904
* the area divided by the total edge lengths
6907
len1= VecLenf(v1->co, v2->co);
6908
len2= VecLenf(v2->co, v3->co);
6909
len3= VecLenf(v3->co, v4->co);
6910
len4= VecLenf(v4->co, v1->co);
6911
len5= VecLenf(v1->co, v3->co);
6912
len6= VecLenf(v2->co, v4->co);
6914
opp1= AreaT3Dfl(v1->co, v2->co, v3->co);
6915
opp2= AreaT3Dfl(v1->co, v3->co, v4->co);
6917
fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
6919
opp1= AreaT3Dfl(v2->co, v3->co, v4->co);
6920
opp2= AreaT3Dfl(v2->co, v4->co, v1->co);
6922
fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
6926
if(dia2.v1==eed->v1 && dia2.v2==eed->v2) {
6933
w= addvlaklist(v1, v2, v3, 0, evl);
6935
UVCOPY(w->tf.uv[0], uv[0]);
6936
UVCOPY(w->tf.uv[1], uv[1]);
6937
UVCOPY(w->tf.uv[2], uv[2]);
6939
w->tf.col[0] = col[0]; w->tf.col[1] = col[1]; w->tf.col[2] = col[2];
6940
w= addvlaklist(v1, v3, v4, 0, evl);
6942
UVCOPY(w->tf.uv[0], uv[0]);
6943
UVCOPY(w->tf.uv[1], uv[2]);
6944
UVCOPY(w->tf.uv[2], uv[3]);
6946
w->tf.col[0] = col[0]; w->tf.col[1] = col[2]; w->tf.col[2] = col[3];
6951
else if(fac1 < fac2) {
6952
if(dia1.v1==eed->v1 && dia1.v2==eed->v2) {
6959
w= addvlaklist(v2, v3, v4, 0, evl);
6961
UVCOPY(w->tf.uv[0], uv[1]);
6962
UVCOPY(w->tf.uv[1], uv[3]);
6963
UVCOPY(w->tf.uv[2], uv[4]);
6965
w= addvlaklist(v1, v2, v4, 0, evl);
6967
UVCOPY(w->tf.uv[0], uv[0]);
6968
UVCOPY(w->tf.uv[1], uv[1]);
6969
UVCOPY(w->tf.uv[2], uv[3]);
6981
free_tagged_edgelist(em->edges.first);
6982
free_tagged_facelist(em->faces.first);
6984
if(onedone==0) break;
6989
allqueue(REDRAWVIEW3D, 0);
6990
makeDispList(G.obedit);
6993
/** tests whether selected mesh objects have tfaces */
6994
static int testSelected_TfaceMesh(void)
7002
if(base->object->type==OB_MESH) {
7003
me= base->object->data;
7013
void join_mesh(void)
7017
Material **matar, *ma;
7019
MVert *mvert, *mvertmain;
7020
MFace *mface = NULL, *mfacemain;
7021
TFace *tface = NULL, *tfacemain;
7022
unsigned int *mcol=NULL, *mcolmain;
7023
float imat[4][4], cmat[4][4];
7024
int a, b, totcol, totvert=0, totface=0, ok=0, vertofs, map[MAXMAT];
7026
int i, j, index, haskey=0;
7027
bDeformGroup *dg, *odg;
7028
MDeformVert *dvert, *dvertmain;
7031
if(G.obedit) return;
7034
if(!ob || ob->type!=OB_MESH) return;
7041
if(base->object->type==OB_MESH) {
7042
me= base->object->data;
7043
totvert+= me->totvert;
7044
totface+= me->totface;
7046
if(base->object == ob) ok= 1;
7057
error("Join with vertex keys not supported");
7060
/* that way the active object is always selected */
7063
if(totvert==0 || totvert>MESH_MAX_VERTS) return;
7065
if(okee("Join selected Meshes")==0) return;
7067
/* new material indices and material array */
7068
matar= MEM_callocN(sizeof(void *)*MAXMAT, "join_mesh");
7071
/* obact materials in new main array, is nicer start! */
7072
for(a=1; a<=ob->totcol; a++) {
7073
matar[a-1]= give_current_material(ob, a);
7074
id_us_plus((ID *)matar[a-1]);
7075
/* increase id->us : will be lowered later */
7081
if(ob!=base->object && base->object->type==OB_MESH) {
7082
me= base->object->data;
7084
// Join this object's vertex groups to the base one's
7085
for (dg=base->object->defbase.first; dg; dg=dg->next){
7086
/* See if this group exists in the object */
7087
for (odg=ob->defbase.first; odg; odg=odg->next){
7088
if (!strcmp(odg->name, dg->name)){
7093
odg = MEM_callocN (sizeof(bDeformGroup), "deformGroup");
7094
memcpy (odg, dg, sizeof(bDeformGroup));
7095
BLI_addtail(&ob->defbase, odg);
7099
if (ob->defbase.first && ob->actdef==0)
7103
for(a=1; a<=base->object->totcol; a++) {
7104
ma= give_current_material(base->object, a);
7106
for(b=0; b<totcol; b++) {
7107
if(ma == matar[b]) break;
7114
if(totcol>=MAXMAT-1) break;
7119
if(totcol>=MAXMAT-1) break;
7125
mvert= mvertmain= MEM_mallocN(totvert*sizeof(MVert), "joinmesh1");
7127
if (totface) mface= mfacemain= MEM_mallocN(totface*sizeof(MFace), "joinmesh2");
7130
if(me->mcol) mcol= mcolmain= MEM_callocN(totface*4*sizeof(int), "joinmesh3");
7133
/* if active object doesn't have Tfaces, but one in the selection does,
7134
make TFaces for active, so we don't lose texture information in the
7136
if(me->tface || testSelected_TfaceMesh()) tface= tfacemain= MEM_callocN(totface*4*sizeof(TFace), "joinmesh4");
7142
dvert= dvertmain= MEM_callocN(totvert*sizeof(MDeformVert), "joinmesh5");
7143
else dvert=dvertmain= NULL;
7148
/* inverse transorm all selected meshes in this object */
7149
Mat4Invert(imat, ob->obmat);
7155
if(base->object->type==OB_MESH) {
7157
me= base->object->data;
7161
memcpy(mvert, me->mvert, me->totvert*sizeof(MVert));
7164
copy_dverts(dvert, me->dvert, me->totvert);
7168
for (i=0; i<me->totvert; i++){
7169
for (j=0; j<dvert[i].totweight; j++){
7170
// Find the old vertex group
7171
odg = BLI_findlink (&base->object->defbase, dvert[i].dw[j].def_nr);
7173
// Search for a match in the new object
7174
for (dg=ob->defbase.first, index=0; dg; dg=dg->next, index++){
7175
if (!strcmp(dg->name, odg->name)){
7176
dvert[i].dw[j].def_nr = index;
7187
if(base->object != ob) {
7188
/* watch this: switch matmul order really goes wrong */
7189
Mat4MulMat4(cmat, base->object->obmat, imat);
7193
Mat4MulVecfl(cmat, mvert->co);
7197
else mvert+= me->totvert;
7200
if(me->mcol) memcpy(mcol, me->mcol, me->totface*4*4);
7201
mcol+= 4*me->totface;
7206
/* make mapping for materials */
7207
memset(map, 0, 4*MAXMAT);
7208
for(a=1; a<=base->object->totcol; a++) {
7209
ma= give_current_material(base->object, a);
7211
for(b=0; b<totcol; b++) {
7212
if(ma == matar[b]) {
7220
memcpy(mface, me->mface, me->totface*sizeof(MFace));
7224
mface->v1+= vertofs;
7225
mface->v2+= vertofs;
7226
if(mface->v3) mface->v3+= vertofs;
7227
if(mface->v4) mface->v4+= vertofs;
7229
mface->mat_nr= map[(int)mface->mat_nr];
7235
if(me->tface) memcpy(tface, me->tface, me->totface*sizeof(TFace));
7236
tface+= me->totface;
7240
vertofs+= me->totvert;
7242
if(base->object!=ob) {
7243
free_and_unlink_base(base);
7252
if(me->mface) MEM_freeN(me->mface);
7253
me->mface= mfacemain;
7254
if(me->mvert) MEM_freeN(me->mvert);
7256
if(me->dvert) free_dverts(me->dvert, me->totvert);
7257
me->dvert = dvertmain;
7259
me->mvert= mvertmain;
7260
if(me->mcol) MEM_freeN(me->mcol);
7261
me->mcol= (MCol *)mcolmain;
7262
if(me->tface) MEM_freeN(me->tface);
7263
me->tface= tfacemain;
7264
me->totvert= totvert;
7265
me->totface= totface;
7267
/* old material array */
7268
for(a=1; a<=ob->totcol; a++) {
7272
for(a=1; a<=me->totcol; a++) {
7276
if(ob->mat) MEM_freeN(ob->mat);
7277
if(me->mat) MEM_freeN(me->mat);
7278
ob->mat= me->mat= 0;
7282
ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
7284
else MEM_freeN(matar);
7286
ob->totcol= me->totcol= totcol;
7289
/* other mesh users */
7290
test_object_materials((ID *)me);
7295
allqueue(REDRAWVIEW3D, 0);
7296
allqueue(REDRAWBUTSSHADING, 0);
7297
makeDispList(G.obedit);
7301
void clever_numbuts_mesh(void)
7303
EditMesh *em = G.editMesh;
7306
eve= em->verts.first;
7308
if(eve->f & 1) break;
7313
add_numbut(0, NUM|FLO, "LocX:", -G.vd->far, G.vd->far, eve->co, 0);
7314
add_numbut(1, NUM|FLO, "LocY:", -G.vd->far, G.vd->far, eve->co+1, 0);
7315
add_numbut(2, NUM|FLO, "LocZ:", -G.vd->far, G.vd->far, eve->co+2, 0);
7317
do_clever_numbuts("Active Vertex", 3, REDRAW);
7321
static void permutate(void *list, int num, int size, int *index)
7329
buf = MEM_mallocN(len, "permutate");
7330
memcpy(buf, list, len);
7332
for (i = 0; i < num; i++) {
7333
memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size);
7338
static MVert *mvertbase;
7339
static MFace *mfacebase;
7341
static int verg_mface(const void *v1, const void *v2)
7348
i1 = ((int *) v1)[0];
7349
i2 = ((int *) v2)[0];
7351
x1 = mfacebase + i1;
7352
x2 = mfacebase + i2;
7354
ve1= mvertbase+x1->v1;
7355
ve2= mvertbase+x2->v1;
7357
if( ve1->co[2] > ve2->co[2] ) return 1;
7358
else if( ve1->co[2] < ve2->co[2]) return -1;
7363
void sort_faces(void)
7371
if(G.obedit) return;
7372
if(ob->type!=OB_MESH) return;
7374
if(okee("Sort Faces in Z")==0) return;
7376
if(me->totface==0) return;
7378
/* create index list */
7379
index = (int *) MEM_mallocN(sizeof(int) * me->totface, "sort faces");
7380
for (i = 0; i < me->totface; i++) {
7383
mvertbase= me->mvert;
7384
mfacebase = me->mface;
7386
/* sort index list instead of faces itself
7387
and apply this permutation to the face list plus
7388
to the texture faces */
7389
qsort(index, me->totface, sizeof(int), verg_mface);
7391
permutate(mfacebase, me->totface, sizeof(MFace), index);
7393
permutate(me->tface, me->totface, sizeof(TFace), index);
7397
allqueue(REDRAWVIEW3D, 0);
7398
makeDispList(G.obedit);
7401
void vertices_to_sphere(void)
7403
EditMesh *em = G.editMesh;
7406
float *curs, len, vec[3], cent[3], fac, facm, imat[3][3], bmat[3][3];
7413
if(button(&perc, 1, 100, "Percentage:")==0) return;
7415
undo_push_mesh("To Sphere");
7420
Mat3CpyMat4(bmat, ob->obmat);
7421
Mat3Inv(imat, bmat);
7424
curs= give_cursor();
7425
cent[0]= curs[0]-ob->obmat[3][0];
7426
cent[1]= curs[1]-ob->obmat[3][1];
7427
cent[2]= curs[2]-ob->obmat[3][2];
7428
Mat3MulVecfl(imat, cent);
7432
eve= em->verts.first;
7436
len+= VecLenf(cent, eve->co);
7442
if(len==0.0) len= 10.0;
7444
eve= em->verts.first;
7447
vec[0]= eve->co[0]-cent[0];
7448
vec[1]= eve->co[1]-cent[1];
7449
vec[2]= eve->co[2]-cent[2];
7453
eve->co[0]= fac*(cent[0]+vec[0]*len) + facm*eve->co[0];
7454
eve->co[1]= fac*(cent[1]+vec[1]*len) + facm*eve->co[1];
7455
eve->co[2]= fac*(cent[2]+vec[2]*len) + facm*eve->co[2];
7461
allqueue(REDRAWVIEW3D, 0);
7462
makeDispList(G.obedit);
7465
/* Got this from scanfill.c. You will need to juggle around the
7466
* callbacks for the scanfill.c code a bit for this to work. */
7467
void fill_mesh(void)
7469
EditMesh *em = G.editMesh;
7471
EditEdge *eed,*e1,*nexted;
7472
EditVlak *evl,*nextvl;
7475
if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return;
7479
undo_push_mesh("Fill");
7481
/* copy all selected vertices */
7482
eve= em->verts.first;
7485
v1= BLI_addfillvert(eve->co);
7492
/* copy all selected edges */
7493
eed= em->edges.first;
7495
if( (eed->v1->f & 1) && (eed->v2->f & 1) ) {
7496
e1= BLI_addfilledge(eed->v1->vn, eed->v2->vn);
7502
/* from all selected faces: remove vertices and edges verwijderen to prevent doubles */
7503
/* all edges add values, faces subtract,
7504
then remove edges with vertices ->h<2 */
7505
evl= em->faces.first;
7509
if( vlakselectedAND(evl, 1) ) {
7513
if(evl->v4) evl->v4->vn->h--;
7519
if(ok) { /* there are faces selected */
7520
eed= filledgebase.first;
7523
if(eed->v1->h<2 || eed->v2->h<2) {
7524
BLI_remlink(&filledgebase,eed);
7530
/* to make edgefill work */
7531
BLI_setScanFillObjectRef(G.obedit);
7532
BLI_setScanFillColourRef(&G.obedit->actcol);
7534
ok= BLI_edgefill(0);
7536
/* printf("time: %d\n",(clock()-tijd)/1000); */
7539
evl= fillvlakbase.first;
7541
addvlaklist(evl->v1->vn, evl->v2->vn, evl->v3->vn, 0, evl);
7545
/* else printf("fill error\n"); */
7552
allqueue(REDRAWVIEW3D, 0);
7553
makeDispList(G.obedit);
7556
/* ***************** */
7558
/* this one for NOT in editmode
7560
(only used by external modules, that is, until now by the
7561
python NMesh module)
7563
TODO: Probably it's better to convert the mesh into a EditMesh, call
7564
vertexnormals() and convert it back to a Mesh again.
7568
void vertexnormals_mesh(Mesh *me, float *extverts)
7572
float n1[3], n2[3], n3[3], n4[3], co[4], fac1, fac2, fac3, fac4, *temp;
7573
float *f1, *f2, *f3, *f4, xn, yn, zn, *normals;
7574
float *v1, *v2, *v3, *v4, len, vnor[3];
7577
if(me->totvert==0) return;
7579
testflip= (me->flag & ME_NOPUNOFLIP)==0;
7580
if((me->flag & ME_TWOSIDED)==0) testflip= 0; /* large angles */
7582
if(me->totface==0) {
7583
/* fake vertex normals for 'halopuno' (render option) */
7585
for(a=0; a<me->totvert; a++, mvert++) {
7586
VECCOPY(n1, mvert->co);
7588
mvert->no[0]= 32767.0*n1[0];
7589
mvert->no[1]= 32767.0*n1[1];
7590
mvert->no[2]= 32767.0*n1[2];
7595
normals= MEM_callocN(me->totvert*3*sizeof(float), "normals");
7597
/* calculate cosine angles, and add to vertex normal */
7600
for(a=0; a<me->totface; a++, mface++) {
7602
if(mface->v3==0) continue;
7605
v1= extverts+3*mface->v1;
7606
v2= extverts+3*mface->v2;
7607
v3= extverts+3*mface->v3;
7608
v4= extverts+3*mface->v4;
7611
v1= (mvert+mface->v1)->co;
7612
v2= (mvert+mface->v2)->co;
7613
v3= (mvert+mface->v3)->co;
7614
v4= (mvert+mface->v4)->co;
7617
VecSubf(n1, v2, v1);
7618
VecSubf(n2, v3, v2);
7623
VecSubf(n3, v1, v3);
7626
co[0]= saacos(-n3[0]*n1[0]-n3[1]*n1[1]-n3[2]*n1[2]);
7627
co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
7628
co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
7632
VecSubf(n3, v4, v3);
7633
VecSubf(n4, v1, v4);
7637
co[0]= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
7638
co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
7639
co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
7640
co[3]= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
7643
CalcNormFloat(v1, v2, v3, vnor);
7645
temp= normals+3*mface->v1;
7646
if(testflip && contrpuntnorm(vnor, temp) ) co[0]= -co[0];
7647
temp[0]+= co[0]*vnor[0];
7648
temp[1]+= co[0]*vnor[1];
7649
temp[2]+= co[0]*vnor[2];
7651
temp= normals+3*mface->v2;
7652
if(testflip && contrpuntnorm(vnor, temp) ) co[1]= -co[1];
7653
temp[0]+= co[1]*vnor[0];
7654
temp[1]+= co[1]*vnor[1];
7655
temp[2]+= co[1]*vnor[2];
7657
temp= normals+3*mface->v3;
7658
if(testflip && contrpuntnorm(vnor, temp) ) co[2]= -co[2];
7659
temp[0]+= co[2]*vnor[0];
7660
temp[1]+= co[2]*vnor[1];
7661
temp[2]+= co[2]*vnor[2];
7664
temp= normals+3*mface->v4;
7665
if(testflip && contrpuntnorm(vnor, temp) ) co[3]= -co[3];
7666
temp[0]+= co[3]*vnor[0];
7667
temp[1]+= co[3]*vnor[1];
7668
temp[2]+= co[3]*vnor[2];
7672
/* normalize vertex normals */
7674
for(a=0; a<me->totvert; a++, mvert++) {
7675
len= Normalise(normals+3*a);
7677
VECCOPY(n1, normals+3*a);
7680
mvert->no[0]= 32767.0*n1[0];
7681
mvert->no[1]= 32767.0*n1[1];
7682
mvert->no[2]= 32767.0*n1[2];
7686
/* vertex normal flipping flags, for during render */
7689
for(a=0; a<me->totface; a++, mface++) {
7692
if(mface->v3==0) continue;
7695
v1= extverts+3*mface->v1;
7696
v2= extverts+3*mface->v2;
7697
v3= extverts+3*mface->v3;
7700
v1= (mvert+mface->v1)->co;
7701
v2= (mvert+mface->v2)->co;
7702
v3= (mvert+mface->v3)->co;
7705
CalcNormFloat(v1, v2, v3, vnor);
7708
f1= normals + 3*mface->v1;
7709
f2= normals + 3*mface->v2;
7710
f3= normals + 3*mface->v3;
7712
fac1= vnor[0]*f1[0] + vnor[1]*f1[1] + vnor[2]*f1[2];
7714
mface->puno = ME_FLIPV1;
7716
fac2= vnor[0]*f2[0] + vnor[1]*f2[1] + vnor[2]*f2[2];
7718
mface->puno += ME_FLIPV2;
7720
fac3= vnor[0]*f3[0] + vnor[1]*f3[1] + vnor[2]*f3[2];
7722
mface->puno += ME_FLIPV3;
7725
f4= normals + 3*mface->v4;
7726
fac4= vnor[0]*f4[0] + vnor[1]*f4[1] + vnor[2]*f4[2];
7728
mface->puno += ME_FLIPV4;
7732
/* proj for cubemap! */
7737
if(zn>xn && zn>yn) mface->puno += ME_PROJXY;
7738
else if(yn>xn && yn>zn) mface->puno += ME_PROJXZ;
7739
else mface->puno += ME_PROJYZ;
7748
static int editmesh_nfaces_selected(void)
7750
EditMesh *em = G.editMesh;
7754
for (evl= em->faces.first; evl; evl= evl->next)
7755
if (vlakselectedAND(evl, SELECT))
7761
static int editmesh_nvertices_selected(void)
7763
EditMesh *em = G.editMesh;
7767
for (eve= em->verts.first; eve; eve= eve->next)
7768
if (eve->f & SELECT)
7774
static void editmesh_calc_selvert_center(float cent_r[3])
7776
EditMesh *em = G.editMesh;
7780
cent_r[0]= cent_r[1]= cent_r[0]= 0.0;
7782
for (eve= em->verts.first; eve; eve= eve->next) {
7783
if (eve->f & SELECT) {
7784
cent_r[0]+= eve->co[0];
7785
cent_r[1]+= eve->co[1];
7786
cent_r[2]+= eve->co[2];
7798
static int tface_is_selected(TFace *tf)
7800
return (!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT));
7803
static int faceselect_nfaces_selected(Mesh *me)
7807
for (i=0; i<me->totface; i++) {
7808
MFace *mf= ((MFace*) me->mface) + i;
7809
TFace *tf= ((TFace*) me->tface) + i;
7811
if (mf->v3 && tface_is_selected(tf))
7818
/* XXX, code for both these functions should be abstract,
7819
* then unified, then written for other things (like objects,
7820
* which would use same as vertices method), then added
7821
* to interface! Hoera! - zr
7823
void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis)
7825
if (!faceselect_nfaces_selected(me)) {
7826
error("No faces selected.");
7831
norm[0]= norm[1]= norm[2]= 0.0;
7832
for (i=0; i<me->totface; i++) {
7833
MFace *mf= ((MFace*) me->mface) + i;
7834
TFace *tf= ((TFace*) me->tface) + i;
7836
if (mf->v3 && tface_is_selected(tf)) {
7837
float *v1, *v2, *v3, fno[3];
7839
v1= me->mvert[mf->v1].co;
7840
v2= me->mvert[mf->v2].co;
7841
v3= me->mvert[mf->v3].co;
7843
float *v4= me->mvert[mf->v4].co;
7844
CalcNormFloat4(v1, v2, v3, v4, fno);
7846
CalcNormFloat(v1, v2, v3, fno);
7855
view3d_align_axis_to_vector(v3d, axis, norm);
7859
void editmesh_align_view_to_selected(View3D *v3d, int axis)
7861
EditMesh *em = G.editMesh;
7862
int nselverts= editmesh_nvertices_selected();
7866
error("No faces or vertices selected.");
7868
error("At least one face or three vertices must be selected.");
7870
} else if (editmesh_nfaces_selected()) {
7874
norm[0]= norm[1]= norm[2]= 0.0;
7875
for (evl= em->faces.first; evl; evl= evl->next) {
7876
if (vlakselectedAND(evl, SELECT)) {
7878
if (evl->v4) CalcNormFloat4(evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co, fno);
7879
else CalcNormFloat(evl->v1->co, evl->v2->co, evl->v3->co, fno);
7880
/* XXX, fixme, should be flipped intp a
7881
* consistent direction. -zr
7889
Mat4Mul3Vecfl(G.obedit->obmat, norm);
7890
view3d_align_axis_to_vector(v3d, axis, norm);
7892
float cent[3], norm[3];
7893
EditVert *eve, *leve= NULL;
7895
norm[0]= norm[1]= norm[2]= 0.0;
7896
editmesh_calc_selvert_center(cent);
7897
for (eve= em->verts.first; eve; eve= eve->next) {
7898
if (eve->f & SELECT) {
7901
CalcNormFloat(cent, leve->co, eve->co, tno);
7903
/* XXX, fixme, should be flipped intp a
7904
* consistent direction. -zr
7914
Mat4Mul3Vecfl(G.obedit->obmat, norm);
7915
view3d_align_axis_to_vector(v3d, axis, norm);
7921
Read a trail of mouse coords and return them as an array of CutCurve structs
7922
len returns number of mouse coords read before commiting with RETKEY
7923
It is up to the caller to free the block when done with it,
7925
this doesn't belong here.....
7928
CutCurve *get_mouse_trail(int *len, char mode){
7930
CutCurve *curve,*temp;
7931
short event, val, ldown=0, restart=0, rubberband=0;
7932
short mval[2], lockaxis=0, lockx=0, locky=0, lastx=0, lasty=0;
7933
int i=0, j, blocks=1, lasti=0;
7936
curve=(CutCurve *)MEM_callocN(1024*sizeof(CutCurve), "MouseTrail");
7939
printf("failed to allocate memory in get_mouse_trail()\n");
7942
mywinset(curarea->win);
7943
glDrawBuffer(GL_FRONT);
7945
headerprint("LMB to draw, Enter to finish, ESC to abort.");
7949
glColor3ub(200, 200, 0);
7953
event=extern_qread(&val); /* Enter or RMB indicates finish */
7955
if(event==RETKEY || event==PADENTER) break;
7958
if( event==ESCKEY || event==RIGHTMOUSE ) {
7959
if (curve) MEM_freeN(curve);
7962
glDrawBuffer(GL_BACK);
7967
if (rubberband) { /* rubberband mode, undraw last rubberband */
7969
sdrawXORline(curve[i-1].x, curve[i-1].y,mval[0], mval[1]);
7975
getmouseco_areawin(mval);
7977
if (lockaxis==1) mval[1]=locky;
7978
if (lockaxis==2) mval[0]=lockx;
7980
if ( ((i==0) || (mval[0]!=curve[i-1].x) || (mval[1]!=curve[i-1].y))
7981
&& (get_mbut() & L_MOUSE) ){ /* record changes only, if LMB down */
7983
lastx=curve[i].x=mval[0];
7984
lasty=curve[i].y=mval[1];
7992
for(j=1;j<i;j++) sdrawXORline(curve[j-1].x, curve[j-1].y, curve[j].x, curve[j].y);
7993
if (rubberband) sdrawXORline(curve[j].x, curve[j].y, mval[0], mval[1]);
8002
if ((event==MIDDLEMOUSE)&&(get_mbut()&M_MOUSE)&&(i)){/*MMB Down*/
8003
/*determine which axis to lock to, or clear if locked */
8004
if (lockaxis) lockaxis=0;
8005
else if (abs(curve[i-1].x-mval[0]) > abs(curve[i-1].y-mval[1])) lockaxis=1;
8014
if ((i>1)&&(i!=lasti)) { /*Draw recorded part of curve */
8015
sdrawline(curve[i-2].x, curve[i-2].y, curve[i-1].x, curve[i-1].y);
8019
if ((i==lasti)&&(i>0)) { /*Draw rubberband */
8021
sdrawXORline(curve[i-1].x, curve[i-1].y,mval[0], mval[1]);
8028
if (i>=blocks*1024) { /* reallocate data if out of room */
8030
curve=(CutCurve *)MEM_callocN((blocks+1)*1024*sizeof(CutCurve), "MouseTrail");
8032
printf("failed to re-allocate memory in get_mouse_trail()\n");
8035
memcpy(curve, temp, blocks*1024*sizeof(CutCurve));
8042
glDrawBuffer(GL_BACK);
8050
/* ******************************************************************** */
8051
/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
8054
Currently mapped to KKey when in MeshEdit mode.
8056
Hit Shift K, Select Centers or Exact
8057
Hold LMB down to draw path, hit RETKEY.
8058
ESC cancels as expected.
8060
Contributed by Robert Wenzlaff (Det. Thorn).
8063
void KnifeSubdivide(char mode){
8064
EditMesh *em = G.editMesh;
8065
int oldcursor, len=0;
8071
if (G.obedit==0) return;
8073
if (editmesh_nvertices_selected() < 2) {
8074
error("No edges are selected to operate on");
8078
if (mode==KNIFE_PROMPT) {
8079
short val= pupmenu("Cut Type %t|Exact Line%x1|Midpoints%x2");
8081
mode= val; // warning, mode is char, pupmenu returns -1 with ESC
8084
undo_push_mesh("Knife");
8086
calc_meshverts_ext(); /*Update screen coords for current window */
8088
/* Set a knife cursor here */
8089
oldcursor=get_cursor();
8091
win=winlay_get_active_window();
8093
SetBlenderCursor(BC_KNIFECURSOR);
8095
curve=get_mouse_trail(&len, TRAIL_MIXED);
8097
if (curve && len && mode){
8098
eed= em->edges.first;
8100
if((eed->v1->f&1)&&(eed->v2->f&1)){
8101
isect=seg_intersect(eed, curve, len);
8102
if (isect) eed->f=1;
8105
//printf("isect=%i\n", isect);
8114
if (mode==1) subdivideflag(1, 0, B_KNIFE|B_PERCENTSUBD);
8115
else if (mode==2) subdivideflag(1, 0, B_KNIFE);
8117
eed=em->edges.first;
8124
/* Return to old cursor and flags...*/
8126
addqueue(curarea->win, REDRAW, 0);
8127
window_set_cursor(win, oldcursor);
8128
if (curve) MEM_freeN(curve);
8131
/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
8133
short seg_intersect(EditEdge *e, CutCurve *c, int len){
8134
#define MAXSLOPE 100000
8136
float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
8137
float y2min, dist, lastdist=0, xdiff2, xdiff1;
8138
float m1, b1, m2, b2, x21, x22, y21, y22, xi;
8139
float yi, x1min, x1max, y1max, y1min, perc=0;
8140
float scr[2], co[4];
8143
/* Get screen coords of verts (v->xs and v->ys clip if off screen */
8144
VECCOPY(co, e->v1->co);
8146
Mat4MulVec4fl(G.obedit->obmat, co);
8147
project_float(co, scr);
8151
VECCOPY(co, e->v2->co);
8153
Mat4MulVec4fl(G.obedit->obmat, co);
8154
project_float(co, scr);
8160
m2=(y22-y21)/xdiff2;
8161
b2= ((x22*y21)-(x21*y22))/xdiff2;
8164
m2=MAXSLOPE; /* Verticle slope */
8167
for (i=0; i<len; i++){
8179
/* Perp. Distance from point to line */
8180
if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
8181
/* change in sign. Skip extra math */
8184
if (i==0) lastdist=dist;
8186
/* if dist changes sign, and intersect point in edge's Bound Box*/
8187
if ((lastdist*dist)<=0){
8188
xdiff1=(x12-x11); /* Equation of line between last 2 points */
8190
m1=(y12-y11)/xdiff1;
8191
b1= ((x12*y11)-(x11*y12))/xdiff1;
8197
x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
8198
x2min=MIN2(x21,x22)-0.001; /* due to round off error */
8199
y2max=MAX2(y21,y22)+0.001;
8200
y2min=MIN2(y21,y22)-0.001;
8202
/* Found an intersect, calc intersect point */
8203
if (m1==m2){ /* co-incident lines */
8204
/* cut at 50% of overlap area*/
8205
x1max=MAX2(x11, x12);
8206
x1min=MIN2(x11, x12);
8207
xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
8209
y1max=MAX2(y11, y12);
8210
y1min=MIN2(y11, y12);
8211
yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
8213
else if (m2==MAXSLOPE){
8217
else if (m1==MAXSLOPE){
8223
yi=(b1*m2-m1*b2)/(m2-m1);
8226
/* Intersect inside bounding box of edge?*/
8227
if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
8228
if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
8229
else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
8230
isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
8240
void LoopMenu(){ /* Called by KKey */
8244
ret=pupmenu("Loop/Cut Menu %t|Face Loop Select %x1|Face Loop Cut %x2|"
8245
"Knife (Exact) %x3|Knife (Midpoints)%x4|");
8249
loopoperations(LOOP_SELECT);
8252
loopoperations(LOOP_CUT);
8255
KnifeSubdivide(KNIFE_EXACT);
8258
KnifeSubdivide(KNIFE_MIDPOINT);
8263
/*********************** EDITMESH UNDO ********************************/
8264
/* Mesh Edit undo by Alexander Ewring, */
8265
/* ported by Robert Wenzlaff */
8267
/* Any meshedit function wishing to create an undo step, calls */
8268
/* undo_push_mesh("menu_name_of_step"); */
8270
Mesh *undo_new_mesh(void)
8272
return(MEM_callocN(sizeof(Mesh), "undo_mesh"));
8275
void undo_free_mesh(Mesh *me)
8277
if(me->mat) MEM_freeN(me->mat);
8278
if(me->orco) MEM_freeN(me->orco);
8279
if(me->mface) MEM_freeN(me->mface);
8280
if(me->tface) MEM_freeN(me->tface);
8281
if(me->mvert) MEM_freeN(me->mvert);
8282
if(me->dvert) free_dverts(me->dvert, me->totvert);
8283
if(me->mcol) MEM_freeN(me->mcol);
8284
if(me->msticky) MEM_freeN(me->msticky);
8285
if(me->bb) MEM_freeN(me->bb);
8286
if(me->disp.first) freedisplist(&me->disp);
1614
/* ******************************************** */
1616
/* *************** UNDO ***************************** */
1617
/* new mesh undo, based on pushing editmesh data itself */
1618
/* reuses same code as for global and curve undo... unify that (ton) */
1620
/* only one 'hack', to save memory it doesn't store the first push, but does a remake editmesh */
1622
/* a compressed version of editmesh data */
1623
typedef struct EditVertC
1629
struct MDeformWeight *dw;
1633
typedef struct EditEdgeC
1636
unsigned char f, h, seam, pad;
1637
short crease, fgoni;
1640
typedef struct EditFaceC
1643
unsigned char mat_nr, flag, f, h, puno, fgonf;
1647
typedef struct UndoMesh {
1652
int totvert, totedge, totface;
1658
static void free_undoMesh(void *umv)
1664
for(a=0, evec= um->verts; a<um->totvert; a++, evec++) {
1665
if(evec->dw) MEM_freeN(evec->dw);
1668
if(um->verts) MEM_freeN(um->verts);
1669
if(um->edges) MEM_freeN(um->edges);
1670
if(um->faces) MEM_freeN(um->faces);
1671
if(um->tfaces) MEM_freeN(um->tfaces);
1675
static void *editMesh_to_undoMesh(void)
1677
EditMesh *em= G.editMesh;
1679
Mesh *me= G.obedit->data;
1683
EditVertC *evec=NULL;
1684
EditEdgeC *eedc=NULL;
1685
EditFaceC *efac=NULL;
1689
um= MEM_callocN(sizeof(UndoMesh), "undomesh");
1691
for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
1692
for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
1693
for(efa=em->faces.first; efa; efa= efa->next) um->totface++;
1697
if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC");
1698
if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC");
1699
if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC");
1701
if(me->tface) tface= um->tfaces= MEM_mallocN(um->totface*sizeof(TFace), "all tfacesC");
1703
//printf("copy editmesh %d\n", um->totvert*sizeof(EditVert) + um->totedge*sizeof(EditEdge) + um->totface*sizeof(EditFace));
1704
//printf("copy undomesh %d\n", um->totvert*sizeof(EditVertC) + um->totedge*sizeof(EditEdgeC) + um->totface*sizeof(EditFaceC));
1706
/* now copy vertices */
1707
for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) {
1708
VECCOPY(evec->co, eve->co);
1709
VECCOPY(evec->no, eve->no);
1713
evec->keyindex= eve->keyindex;
1714
evec->totweight= eve->totweight;
1715
evec->dw= MEM_dupallocN(eve->dw);
1717
eve->vn= (EditVert *)a;
1721
for(eed=em->edges.first; eed; eed= eed->next, eedc++) {
1722
eedc->v1= (int)eed->v1->vn;
1723
eedc->v2= (int)eed->v2->vn;
1726
eedc->seam= eed->seam;
1727
eedc->crease= (short)(eed->crease*255.0);
1728
eedc->fgoni= eed->fgoni;
1732
for(efa=em->faces.first; efa; efa= efa->next, efac++) {
1733
efac->v1= (int)efa->v1->vn;
1734
efac->v2= (int)efa->v2->vn;
1735
efac->v3= (int)efa->v3->vn;
1736
if(efa->v4) efac->v4= (int)efa->v4->vn;
1739
efac->mat_nr= efa->mat_nr;
1740
efac->flag= efa->flag;
1743
efac->puno= efa->puno;
1744
efac->fgonf= efa->fgonf;
1755
static void undoMesh_to_editMesh(void *umv)
1758
EditMesh *em= G.editMesh;
1759
EditVert *eve, **evar=NULL;
1768
free_editMesh(G.editMesh);
1771
memset(em, 0, sizeof(EditMesh));
1773
init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
1775
/* now copy vertices */
1776
if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar");
1777
for(a=0, evec= um->verts; a<um->totvert; a++, evec++) {
1778
eve= addvertlist(evec->co);
1781
VECCOPY(eve->no, evec->no);
1784
eve->totweight= evec->totweight;
1785
eve->keyindex= evec->keyindex;
1786
eve->dw= MEM_dupallocN(evec->dw);
1790
for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) {
1791
eed= addedgelist(evar[eedc->v1], evar[eedc->v2], NULL);
1795
eed->seam= eedc->seam;
1796
eed->fgoni= eedc->fgoni;
1797
eed->crease= ((float)eedc->crease)/255.0;
1802
for(a=0, efac= um->faces; a<um->totface; a++, efac++) {
1804
efa= addfacelist(evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL);
1806
efa= addfacelist(evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL);
1808
efa->mat_nr= efac->mat_nr;
1809
efa->flag= efac->flag;
1812
efa->puno= efac->puno;
1813
efa->fgonf= efac->fgonf;
1821
end_editmesh_fastmalloc();
1822
if(evar) MEM_freeN(evar);
1826
/* and this is all the undo system needs to know */
8291
1827
void undo_push_mesh(char *name)
8298
G.undo_edit_level++;
8300
if (G.undo_edit_level<0) {
8301
printf("undo: ERROR: G.undo_edit_level negative\n");
8306
if (G.undo_edit[G.undo_edit_level].datablock != 0) {
8307
undo_free_mesh(G.undo_edit[G.undo_edit_level].datablock);
8309
if (strcmp(name, "U")!=0) {
8310
for (i=G.undo_edit_level+1; i<(U.undosteps-1); i++) {
8311
if (G.undo_edit[i].datablock != 0) {
8312
undo_free_mesh(G.undo_edit[i].datablock);
8313
G.undo_edit[i].datablock= 0;
8316
G.undo_edit_highest= G.undo_edit_level;
8319
me= undo_new_mesh();
8321
if (G.undo_edit_level>=U.undosteps) {
8322
G.undo_edit_level--;
8323
undo_free_mesh((Mesh*)G.undo_edit[0].datablock);
8324
G.undo_edit[0].datablock= 0;
8325
for (i=0; i<(U.undosteps-1); i++) {
8326
G.undo_edit[i]= G.undo_edit[i+1];
8330
if (strcmp(name, "U")!=0) strcpy(G.undo_edit[G.undo_edit_level].name, name);
8331
//printf("undo: saving block: %d [%s]\n", G.undo_edit_level, G.undo_edit[G.undo_edit_level].name);
8333
G.undo_edit[G.undo_edit_level].datablock= (void*)me;
8334
load_editMesh_real(me, 1);
8337
void undo_pop_mesh(int steps) /* steps == 1 is one step */
8339
if (G.undo_edit_level > (steps-2)) {
8340
undo_push_mesh("U");
8341
G.undo_edit_level-= steps;
8342
//printf("undo: restoring block: %d [%s]\n", G.undo_edit_level, G.undo_edit[G.undo_edit_level].name); -
8343
make_editMesh_real((Mesh*)G.undo_edit[G.undo_edit_level].datablock);
8344
allqueue(REDRAWVIEW3D, 0);
8345
makeDispList(G.obedit);
8346
G.undo_edit_level--;
8347
} else error("Can't undo");
8351
void undo_redo_mesh(void)
8353
if ( (G.undo_edit[G.undo_edit_level+2].datablock) &&
8354
( (G.undo_edit_level+1) <= G.undo_edit_highest ) ) {
8355
G.undo_edit_level++;
8356
//printf("redo: restoring block: %d [%s]\n", G.undo_edit_level+1, G.undo_edit[G.undo_edit_level+1].name);-
8357
make_editMesh_real((Mesh*)G.undo_edit[G.undo_edit_level+1].datablock);
8358
allqueue(REDRAWVIEW3D, 0);
8359
makeDispList(G.obedit);
8360
} else error("Can't redo");
8363
void undo_clear_mesh(void)
8368
for (i=0; i<=UNDO_EDIT_MAX; i++) {
8369
me= (Mesh*) G.undo_edit[i].datablock;
8371
//printf("undo: freeing %d\n", i);
8373
G.undo_edit[i].datablock= 0;
8378
void undo_menu_mesh(void)
8382
char menu[2080], temp[64];
8386
strcpy(menu, "UNDO %t|%l");
8387
strcat(menu, "|All changes%x1|%l");
8389
for (i=G.undo_edit_level; i>=0; i--) {
8390
snprintf(temp, 64, "|%s%%x%d", G.undo_edit[i].name, i+2);
8394
event=pupmenu_col(menu, 20);
8398
if (event==1) remake_editMesh();
8399
else undo_pop_mesh(G.undo_edit_level-event+3);
8402
/******************* BEVEL CODE STARTS HERE ********************/
8404
void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3])
8406
float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac;
8420
if (ac == 1 || ac == -1) {
8421
midvec[0] = midvec[1] = midvec[2] = 0;
8425
fac = sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1);
8426
VecAddf(mid, n_c, n_a);
8428
VecMulf(mid, d * fac);
8429
VecAddf(mid, mid, v2);
8430
VecCopyf(midvec, mid);
8433
/* Finds the new point using the sinus law to extrapolate a triangle
8434
Lots of sqrts which would not be good for a real time algo
8435
Using the mid point of the extrapolation of both sides
8436
Useless for coplanar quads, but that doesn't happen too often */
8437
void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3]) {
8438
float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3];
8448
s_b = sqrt(1 - (s_b * s_b));
8450
s_a = sqrt(1 - (s_a * s_a));
8453
s_c = sqrt(1 - (s_c * s_c));
8455
l_b = s_b * l_a / s_a;
8456
l_c = s_c * l_a / s_a;
8461
VecAddf(Pos1, v2, c);
8462
VecAddf(Pos2, v3, b);
8464
VecAddf(Dir, Pos1, Pos2);
8467
bevel_displace_vec(midvec, v3, Dir, v2, d, no);
8472
char detect_wrap(float *o_v1, float *o_v2, float *v1, float *v2, float *no) {
8473
float o_a[3], a[3], o_c[3], c[3];
8475
VecSubf(o_a, o_v1, o_v2);
8478
Crossf(o_c, o_a, no);
8481
if (Inpf(c, o_c) <= 0)
8487
// Detects and fix a quad wrapping after the resize
8488
// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal
8489
void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float *no) {
8493
// Quads can wrap partially. Watch out
8494
wrap[0] = detect_wrap(o_v1, o_v2, v1, v2, no); // Edge 1-2
8495
wrap[1] = detect_wrap(o_v2, o_v3, v2, v3, no); // Edge 2-3
8496
wrap[2] = detect_wrap(o_v3, o_v4, v3, v4, no); // Edge 3-4
8497
wrap[3] = detect_wrap(o_v4, o_v1, v4, v1, no); // Edge 4-1
8500
if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 0) {
8501
fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no);
8506
else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) {
8507
fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no);
8512
else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
8513
fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no);
8518
else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) {
8519
fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no);
8523
// Edge 2 and 4 inverted
8524
else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 1) {
8525
VecAddf(vec, v2, v3);
8529
VecAddf(vec, v1, v4);
8534
// Edge 1 and 3 inverted
8535
else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
8536
VecAddf(vec, v1, v2);
8540
VecAddf(vec, v3, v4);
8546
else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1) {
8547
VecAddf(vec, v1, v2);
8548
VecAddf(vec, vec, v3);
8549
VecAddf(vec, vec, v4);
8559
// Detects and fix a tri wrapping after the resize
8560
// Arguments are the orginal verts followed by the final verts and the normal
8561
// Triangles cannot wrap partially (not in this situation
8562
void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3, float *no) {
8563
if (detect_wrap(o_v1, o_v2, v1, v2, no)) {
8565
VecAddf(vec, o_v1, o_v2);
8566
VecAddf(vec, vec, o_v3);
8567
VecMulf(vec, 1.0/3.0);
8574
void bevel_shrink_faces(float d, int flag)
8576
EditMesh *em = G.editMesh;
8578
float vec[3], no[3], v1[3], v2[3], v3[3], v4[3];
8580
/* move edges of all faces with evl->f1 & flag closer towards their centres */
8581
evl= em->faces.first;
8583
if (evl->f1 & flag) {
8584
VECCOPY(v1, evl->v1->co);
8585
VECCOPY(v2, evl->v2->co);
8586
VECCOPY(v3, evl->v3->co);
8587
VECCOPY(no, evl->n);
8588
if (evl->v4 == NULL) {
8589
bevel_displace_vec(vec, v1, v2, v3, d, no);
8590
VECCOPY(evl->v2->co, vec);
8591
bevel_displace_vec(vec, v2, v3, v1, d, no);
8592
VECCOPY(evl->v3->co, vec);
8593
bevel_displace_vec(vec, v3, v1, v2, d, no);
8594
VECCOPY(evl->v1->co, vec);
8596
fix_bevel_tri_wrap(v1, v2, v3, evl->v1->co, evl->v2->co, evl->v3->co, no);
8598
VECCOPY(v4, evl->v4->co);
8599
bevel_displace_vec(vec, v1, v2, v3, d, no);
8600
VECCOPY(evl->v2->co, vec);
8601
bevel_displace_vec(vec, v2, v3, v4, d, no);
8602
VECCOPY(evl->v3->co, vec);
8603
bevel_displace_vec(vec, v3, v4, v1, d, no);
8604
VECCOPY(evl->v4->co, vec);
8605
bevel_displace_vec(vec, v4, v1, v2, d, no);
8606
VECCOPY(evl->v1->co, vec);
8608
fix_bevel_quad_wrap(v1, v2, v3, v4, evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co, d, no);
8615
void bevel_shrink_draw(float d, int flag)
8617
EditMesh *em = G.editMesh;
8619
float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3];
8621
/* move edges of all faces with evl->f1 & flag closer towards their centres */
8622
evl= em->faces.first;
8624
VECCOPY(v1, evl->v1->co);
8625
VECCOPY(v2, evl->v2->co);
8626
VECCOPY(v3, evl->v3->co);
8627
VECCOPY(no, evl->n);
8628
if (evl->v4 == NULL) {
8629
bevel_displace_vec(vec, v1, v2, v3, d, no);
8631
bevel_displace_vec(vec, v2, v3, v1, d, no);
8633
bevel_displace_vec(vec, v3, v1, v2, d, no);
8636
fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3, no);
8651
VECCOPY(v4, evl->v4->co);
8652
bevel_displace_vec(vec, v4, v1, v2, d, no);
8654
bevel_displace_vec(vec, v1, v2, v3, d, no);
8656
bevel_displace_vec(vec, v2, v3, v4, d, no);
8658
bevel_displace_vec(vec, v3, v4, v1, d, no);
8661
fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no);
8684
void bevel_mesh(float bsize, int allfaces)
8686
EditMesh *em = G.editMesh;
8688
/* Enables debug printfs and assigns material indices: */
8690
/* 3 = fill polygon (vertex clusters) */
8692
EditVlak *evl, *example; //, *nextvl;
8693
EditEdge *eed, *eed2;
8694
EditVert *neweve[1024], *eve, *eve2, *eve3, *v1, *v2, *v3, *v4; //, *eve4;
8695
float con1, con2, con3;
8696
//short found4, search;
8697
//float f1, f2, f3, f4;
8698
float cent[3], min[3], max[3];
8704
removedoublesflag(1, limit);
8706
/* tag all original faces */
8707
evl= em->faces.first;
8709
if (vlakselectedAND(evl, 1)||allfaces) {
8714
if (evl->v4) evl->v4->f |= 128;
8719
if (evl->v4) evl->v4->f &= ~64;
8725
fprintf(stderr,"bevel_mesh: split\n");
8728
evl= em->faces.first;
8732
v1= addvertlist(evl->v1->co);
8733
v1->f= evl->v1->f & ~128;
8736
v1->totweight = evl->v1->totweight;
8737
if (evl->v1->totweight){
8738
v1->dw = MEM_mallocN (evl->v1->totweight * sizeof(MDeformWeight), "deformWeight");
8739
memcpy (v1->dw, evl->v1->dw, evl->v1->totweight * sizeof(MDeformWeight));
8744
v1= addvertlist(evl->v2->co);
8745
v1->f= evl->v2->f & ~128;
8748
v1->totweight = evl->v2->totweight;
8749
if (evl->v2->totweight){
8750
v1->dw = MEM_mallocN (evl->v2->totweight * sizeof(MDeformWeight), "deformWeight");
8751
memcpy (v1->dw, evl->v2->dw, evl->v2->totweight * sizeof(MDeformWeight));
8756
v1= addvertlist(evl->v3->co);
8757
v1->f= evl->v3->f & ~128;
8760
v1->totweight = evl->v3->totweight;
8761
if (evl->v3->totweight){
8762
v1->dw = MEM_mallocN (evl->v3->totweight * sizeof(MDeformWeight), "deformWeight");
8763
memcpy (v1->dw, evl->v3->dw, evl->v3->totweight * sizeof(MDeformWeight));
8769
v1= addvertlist(evl->v4->co);
8770
v1->f= evl->v4->f & ~128;
8773
v1->totweight = evl->v4->totweight;
8774
if (evl->v4->totweight){
8775
v1->dw = MEM_mallocN (evl->v4->totweight * sizeof(MDeformWeight), "deformWeight");
8776
memcpy (v1->dw, evl->v4->dw, evl->v4->totweight * sizeof(MDeformWeight));
8783
addedgelist(evl->e1->v1->vn,evl->e1->v2->vn);
8784
addedgelist(evl->e2->v1->vn,evl->e2->v2->vn);
8785
addedgelist(evl->e3->v1->vn,evl->e3->v2->vn);
8786
if (evl->e4) addedgelist(evl->e4->v1->vn,evl->e4->v2->vn);
8793
addvlaklist(v1, v2, v3, v4, evl);
8798
addvlaklist(v1, v2, v3, 0, evl);
8809
/* tag all faces for shrink*/
8810
evl= em->faces.first;
8812
if (vlakselectedAND(evl, 1)||allfaces) {
8819
fprintf(stderr,"bevel_mesh: make edge quads\n");
8822
/* find edges that are on each other and make quads between them */
8824
eed= em->edges.first;
8827
if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces) eed->f1 |= 4; /* original edges */
8832
eed= em->edges.first;
8834
if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) {
8835
eed2= em->edges.first;
8837
if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) {
8839
(eed->v1 != eed2->v1) &&
8840
(eed->v1 != eed2->v2) &&
8841
(eed->v2 != eed2->v1) &&
8842
(eed->v2 != eed2->v2) && (
8843
( VecCompare(eed->v1->co, eed2->v1->co, limit) &&
8844
VecCompare(eed->v2->co, eed2->v2->co, limit) ) ||
8845
( VecCompare(eed->v1->co, eed2->v2->co, limit) &&
8846
VecCompare(eed->v2->co, eed2->v1->co, limit) ) ) )
8850
fprintf(stderr, "bevel_mesh: edge quad\n");
8853
eed->f1 |= 2; /* these edges are finished */
8857
evl= em->faces.first; /* search example vlak (for mat_nr, ME_SMOOTH, ...) */
8859
if ( (evl->e1 == eed) ||
8862
(evl->e4 && (evl->e4 == eed)) ) {
8866
if (evl) evl= evl->next;
8869
neweve[0]= eed->v1; neweve[1]= eed->v2;
8870
neweve[2]= eed2->v1; neweve[3]= eed2->v2;
8872
if(exist_vlak(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
8875
if (VecCompare(eed->v1->co, eed2->v2->co, limit)) {
8876
evl= addvlaklist(neweve[0], neweve[1], neweve[2], neweve[3], example);
8878
evl= addvlaklist(neweve[0], neweve[2], neweve[3], neweve[1], example);
8883
CalcNormFloat(evl->v1->co, evl->v2->co, evl->v3->co, evl->n);
8884
inp= evl->n[0]*G.vd->viewmat[0][2] + evl->n[1]*G.vd->viewmat[1][2] + evl->n[2]*G.vd->viewmat[2][2];
8885
if(inp < 0.0) flipvlak(evl);
8889
} else fprintf(stderr,"bevel_mesh: error creating face\n");
8894
if (eed2) eed2= eed2->next;
8900
eed= em->edges.first;
8911
fprintf(stderr,"bevel_mesh: find clusters\n");
8914
/* Look for vertex clusters */
8916
eve= em->verts.first;
8918
eve->f &= ~(64|128);
8923
/* eve->f: 128: first vertex in a list (->vn) */
8924
/* 64: vertex is in a list */
8926
eve= em->verts.first;
8928
eve2= em->verts.first;
8931
if ((eve2 != eve) && ((eve2->f & (64|128))==0)) {
8932
if (VecCompare(eve->co, eve2->co, limit)) {
8933
if ((eve->f & (128|64)) == 0) {
8934
/* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */
8938
} else if ((eve->f & 64) == 0) {
8939
/* fprintf(stderr," *\n"); */
8940
if (eve3) eve3->vn= eve2;
8948
if (eve3) eve3->vn= NULL;
8955
fprintf(stderr,"bevel_mesh: shrink faces\n");
8958
bevel_shrink_faces(bsize, 2);
8961
fprintf(stderr,"bevel_mesh: fill clusters\n");
8964
/* Make former vertex clusters faces */
8966
eve= em->verts.first;
8972
eve= em->verts.first;
8988
evl= em->faces.first; /* search example vlak */
8990
if ( (evl->v1 == neweve[0]) ||
8991
(evl->v2 == neweve[0]) ||
8992
(evl->v3 == neweve[0]) ||
8993
(evl->v4 && (evl->v4 == neweve[0])) ) {
8997
if (evl) evl= evl->next;
9000
fprintf(stderr,"bevel_mesh: Making %d-gon\n", a);
9003
cent[0]= cent[1]= cent[2]= 0.0;
9004
INIT_MINMAX(min, max);
9005
for (b=0; b<a; b++) {
9006
VecAddf(cent, cent, neweve[b]->co);
9007
DO_MINMAX(neweve[b]->co, min, max);
9009
cent[0]= (min[0]+max[0])/2;
9010
cent[1]= (min[1]+max[1])/2;
9011
cent[2]= (min[2]+max[2])/2;
9012
eve2= addvertlist(cent);
9014
eed= em->edges.first;
9018
if ((neweve[b]==eed->v1) || (neweve[b]==eed->v2)) c++;
9020
if(exist_vlak(eed->v1, eed->v2, eve2, 0)==0) {
9021
evl= addvlaklist(eed->v1, eed->v2, eve2, 0, example);
9030
if(exist_vlak(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
9031
con1= convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co);
9032
con2= convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co);
9033
con3= convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co);
9034
if(con1>=con2 && con1>=con3)
9035
evl= addvlaklist(neweve[0], neweve[1], neweve[2], neweve[3], example);
9036
else if(con2>=con1 && con2>=con3)
9037
evl= addvlaklist(neweve[0], neweve[2], neweve[3], neweve[1], example);
9039
evl= addvlaklist(neweve[0], neweve[2], neweve[1], neweve[3], example);
9043
if(exist_vlak(neweve[0], neweve[1], neweve[2], 0)==0)
9044
evl= addvlaklist(neweve[0], neweve[1], neweve[2], 0, example);
9048
CalcNormFloat(neweve[0]->co, neweve[1]->co, neweve[2]->co, evl->n);
9049
inp= evl->n[0]*G.vd->viewmat[0][2] + evl->n[1]*G.vd->viewmat[1][2] + evl->n[2]*G.vd->viewmat[2][2];
9050
if(inp < 0.0) flipvlak(evl);
9060
eve= em->verts.first;
9063
eve->f &= ~(128|64);
9068
recalc_editnormals();
9071
allqueue(REDRAWVIEW3D, 0);
9072
makeDispList(G.obedit);
9074
removedoublesflag(1, limit);
9079
void bevel_mesh_recurs(float bsize, short recurs, int allfaces)
9085
for (nr=0; nr<recurs; nr++) {
9086
bevel_mesh(d, allfaces);
9087
if (nr==0) d /= 3; else d /= 2;
9093
char Finished = 0, Canceled = 0, str[100], Recalc = 0;
9094
short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr;
9095
float vec[3], d, drawd=0.0, centre[3], fac = 1;
9097
getmouseco_areawin(mval);
9098
oval[0] = mval[0]; oval[1] = mval[1];
9100
// Silly hackish code to initialise the variable (warning if not done)
9101
// while still drawing in the first iteration (and without using another variable)
9102
curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
9104
window_to_3d(centre, mval[0], mval[1]);
9106
if(button(&recurs, 1, 4, "Recurs:")==0) return;
9108
for (nr=0; nr<recurs-1; nr++) {
9109
if (nr==0) fac += 1.0/3.0; else fac += 1.0/(3 * nr * 2.0);
9112
SetBlenderCursor(SYSCURSOR);
9114
while (Finished == 0)
9116
getmouseco_areawin(mval);
9117
if (mval[0] != curval[0] || mval[1] != curval[1] || (Recalc == 1))
9120
curval[0] = mval[0];
9121
curval[1] = mval[1];
9123
window_to_3d(vec, mval[0]-oval[0], mval[1]-oval[1]);
9124
d = Normalise(vec) / 10;
9128
if (G.qual & LR_CTRLKEY)
9129
drawd = (float) floor(drawd * 10.0)/10.0;
9130
if (G.qual & LR_SHIFTKEY)
9133
/*------------- Preview lines--------------- */
9135
/* uses callback mechanism to draw it all in current area */
9136
scrarea_do_windraw(curarea);
9138
/* set window matrix to perspective, default an area returns with buttons transform */
9140
/* make a copy, for safety */
9142
/* multiply with the object transformation */
9143
mymultmatrix(G.obedit->obmat);
9145
glColor3ub(255, 255, 0);
9147
// PREVIEW CODE GOES HERE
9148
bevel_shrink_draw(drawd, 2);
9150
/* restore matrix transform */
9153
sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd);
9156
/* this also verifies other area/windows for clean swap */
9157
screen_swapbuffers();
9161
glDrawBuffer(GL_FRONT);
9163
BIF_ThemeColor(TH_WIRE);
9166
glBegin(GL_LINE_STRIP);
9173
glFinish(); // flush display for frontbuffer
9174
glDrawBuffer(GL_BACK);
9177
unsigned short val=0;
9178
event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
9180
/* val==0 on key-release event */
9181
if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)){
9182
if (event==RIGHTMOUSE || event==ESCKEY)
9186
else if (val && event==SPACEKEY) {
9187
if (fbutton(&d, 0.000, 10.000, 10, 0, "Width:")!=0) {
9193
/* On any other keyboard event, recalc */
9200
SetBlenderCursor(BC_WAITCURSOR);
9201
undo_push_mesh("Bevel");
9202
bevel_mesh_recurs(drawd/fac, recurs, 1);
9204
SetBlenderCursor(SYSCURSOR);
9208
void select_non_manifold(void)
9210
EditMesh *em = G.editMesh;
9215
/* Selects isolated verts, and edges that do not have 2 neighboring
9220
eve= em->verts.first;
9222
/* this will count how many edges are connected
9228
eed= em->edges.first;
9230
/* this will count how many faces are connected to
9233
/* increase edge count for verts */
9239
evl= em->faces.first;
9241
/* increase face count for edges */
9250
/* select verts that are attached to an edge that does not
9251
* have 2 neighboring faces */
9252
eed= em->edges.first;
9255
if (!eed->v1->h) eed->v1->f |= 1;
9256
if (!eed->v2->h) eed->v2->f |= 1;
9261
/* select isolated verts */
9262
eve= em->verts.first;
9265
if (!eve->h) eve->f |= 1;
9271
addqueue(curarea->win, REDRAW, 0);
9275
void select_more(void)
9277
EditMesh *em = G.editMesh;
9281
eve= em->verts.first;
9287
eed= em->edges.first;
9297
eve= em->verts.first;
9300
if (!eve->h) eve->f |= 1;
9306
addqueue(curarea->win, REDRAW, 0);
9309
void select_less(void)
9311
EditMesh *em = G.editMesh;
9316
/* eve->f1 & 1 => isolated */
9317
/* eve->f1 & 2 => on an edge */
9318
/* eve->f1 & 4 => shares edge with a deselected vert */
9319
/* eve->f1 & 8 => at most one neighbor */
9321
eve= em->verts.first;
9323
/* assume vert is isolated unless proven otherwise, */
9324
/* assume at most one neighbor too */
9330
eed= em->edges.first;
9332
/* this will count how many faces are connected to
9336
/* if vert wasn't isolated, it now has more than one neighbor */
9337
if (~eed->v1->f1 & 1) eed->v1->f1 &= ~8;
9338
if (~eed->v2->f1 & 1) eed->v2->f1 &= ~8;
9340
/* verts on edge are clearly not isolated */
9344
/* if one of the verts on the edge is deselected,
9345
* deselect the other */
9346
if ( !(eed->v1->h) && (~eed->v1->f & 1) )
9348
if ( !(eed->v2->h) && (~eed->v2->f & 1) )
9354
evl= em->faces.first;
9356
/* increase face count for edges */
9366
eed= em->edges.first;
9368
/* if the edge has only one neighboring face, then
9369
* deselect attached verts */
9378
/* deselect verts */
9379
eve= em->verts.first;
9389
allqueue(REDRAWVIEW3D, 0);
9393
void selectrandom_mesh(void) /* randomly selects a user-set % of vertices */
9395
EditMesh *em = G.editMesh;
9397
int newsel = 0; /* to decide whether to redraw or not */
9400
if(G.obedit==0) return;
9402
/* Get the percentage of vertices to randomly select as 'randfac' */
9403
if(button(&randfac,0, 100,"Percentage:")==0) return;
9405
if(G.obedit->lay & G.vd->lay) {
9406
eve= em->verts.first;
9408
BLI_srand( BLI_rand() ); /* random seed */
9409
if ( (BLI_frand() * 100) < randfac) {
9413
/* Deselect other vertices
9415
* - Commenting this out makes it add to the selection,
9416
* rather than replace it.
9417
* eve->f &= ~SELECT;
9423
allqueue(REDRAWVIEW3D, 0);
9427
/* this utility function checks to see if 2 edit edges share a face,
9428
returns 1 if they do
9429
returns 0 if they do not, or if the function is passed the same edge 2 times
9431
short sharesFace(EditEdge* e1, EditEdge* e2)
9433
EditMesh *em = G.editMesh;
9434
EditVlak *search=NULL;
9435
search = em->faces.first;
9441
((search->e1 == e1 || search->e2 == e1) || (search->e3 == e1 || search->e4 == e1)) &&
9442
((search->e1 == e2 || search->e2 == e2) || (search->e3 == e2 || search->e4 == e2))
9446
search = search->next;
9450
/* This function selects a vertex loop based on a each succesive edge having a valance of 4
9451
and not sharing a face with the previous edge */
9452
void vertex_loop_select()
9454
EditMesh *em = G.editMesh;
9455
EditVert *v1=NULL,*v2=NULL;
9456
EditEdge *search=NULL,*startEdge=NULL,*valSearch = NULL,*nearest = NULL,*compEdge;
9457
EditEdge *EdgeVal[5] = {NULL,NULL,NULL,NULL,NULL};
9458
short numEdges=0,curEdge = 0,looking = 1,edgeValCount = 0,i=0,looped = 0,choosing = 1,event,noloop=0,cancel=0, val;
9460
short mvalo[2] = {0,0}, mval[2];
9462
undo_push_mesh("Vertex Loop Select");
9463
SetBlenderCursor(BC_VLOOPCURSOR);
9464
for(search=em->edges.first;search;search=search->next)
9467
/* start with v1 and go in one direction. */
9470
getmouseco_areawin(mval);
9471
if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
9476
scrarea_do_windraw(curarea);
9477
nearest = findnearestedge();
9479
for(search = em->edges.first;search;search=search->next)
9482
compEdge = startEdge = nearest;
9489
/*Find Edges that have v1*/
9491
EdgeVal[0] = EdgeVal[1] = EdgeVal[2] = NULL;
9493
for(valSearch = em->edges.first;valSearch;valSearch = valSearch->next){
9494
if(valSearch->v1 == v1 || valSearch->v2 == v1){
9495
if(valSearch != compEdge){
9496
if((valSearch->v1->h == 0) && (valSearch->v2->h == 0)){
9498
EdgeVal[edgeValCount] = valSearch;
9502
if(edgeValCount == 3)break;
9504
/* Check that there was a valance of 4*/
9505
if(edgeValCount != 2){
9511
/* There were 3 edges, so find the one that does not share the previous edge */
9513
if(sharesFace(compEdge,EdgeVal[i]) == 0){
9514
/* We went all the way around the loop */
9515
if(EdgeVal[i] == nearest){
9521
/* we are still in the loop, so add the next edge*/
9523
EdgeVal[i]->f |= 32;
9524
compEdge = EdgeVal[i];
9525
if(compEdge->v1 == v1)
9536
while(looking/* && !looped*/){
9537
/*Find Edges that have v1*/
9539
EdgeVal[0] = EdgeVal[1] = EdgeVal[2] = NULL;
9541
for(valSearch = em->edges.first;valSearch;valSearch = valSearch->next){
9542
if(valSearch->v1 == v2 || valSearch->v2 == v2){
9543
if(valSearch != compEdge){
9544
if((valSearch->v1->h == 0) && (valSearch->v2->h == 0)){
9546
EdgeVal[edgeValCount] = valSearch;
9550
if(edgeValCount == 3)break;
9552
/* Check that there was a valance of 4*/
9553
if(edgeValCount != 2){
9559
/* There were 3 edges, so find the one that does not share the previous edge */
9561
if(sharesFace(compEdge,EdgeVal[i]) == 0){
9562
/* We went all the way around the loop */
9563
if(EdgeVal[i] == nearest){
9569
/* we are still in the loop, so add the next edge*/
9571
EdgeVal[i]->f |= 32;
9572
compEdge = EdgeVal[i];
9573
if(compEdge->v1 == v2)
9582
/* set up for opengl drawing in the 3d window */
9585
mymultmatrix(G.obedit->obmat);
9586
glColor3ub(0, 255, 255);
9587
for(search = em->edges.first;search;search= search->next){
9590
glVertex3f(search->v1->co[0],search->v1->co[1],search->v1->co[2]);
9591
glVertex3f(search->v2->co[0],search->v2->co[1],search->v2->co[2]);
9600
screen_swapbuffers();
9606
event= extern_qread(&val);
9607
if(val && ((event==LEFTMOUSE || event==RETKEY) || event == MIDDLEMOUSE))
9614
if(val && (event==ESCKEY || event==RIGHTMOUSE ))
9620
if(val && (event==BKEY && G.qual==LR_ALTKEY ))
9623
SetBlenderCursor(SYSCURSOR);
9624
loopoperations(LOOP_SELECT);
9630
/* If this is a unmodified select, clear the selection */
9631
if(!(G.qual & LR_SHIFTKEY) && !(G.qual & LR_ALTKEY)){
9632
for(search = em->edges.first;search;search= search->next){
9633
search->v1->f &= !1;
9634
search->v2->f &= !1;
9637
/* Alt was not pressed, so add to the selection */
9638
if(!(G.qual & LR_ALTKEY)){
9639
for(search = em->edges.first;search;search= search->next){
9647
/* alt was pressed, so subtract from the selection */
9650
for(search = em->edges.first;search;search= search->next){
9652
search->v1->f &= !1;
9653
search->v2->f &= !1;
9661
addqueue(curarea->win, REDRAW, 1);
9662
SetBlenderCursor(SYSCURSOR);
9666
void editmesh_select_by_material(int index) {
9667
EditMesh *em = G.editMesh;
9670
for (evl=em->faces.first; evl; evl= evl->next) {
9671
if (evl->mat_nr==index) {
9672
if(evl->v1->h==0) evl->v1->f |= 1;
9673
if(evl->v2->h==0) evl->v2->f |= 1;
9674
if(evl->v3->h==0) evl->v3->f |= 1;
9675
if(evl->v4 && evl->v4->h==0) evl->v4->f |= 1;
9680
void editmesh_deselect_by_material(int index) {
9681
EditMesh *em = G.editMesh;
9684
for (evl=em->faces.first; evl; evl= evl->next) {
9685
if (evl->mat_nr==index) {
9686
if(evl->v1->h==0) evl->v1->f &= ~1;
9687
if(evl->v2->h==0) evl->v2->f &= ~1;
9688
if(evl->v3->h==0) evl->v3->f &= ~1;
9689
if(evl->v4 && evl->v4->h==0) evl->v4->f &= ~1;
1829
undo_editmode_push(name, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh);
1834
/* *************** END UNDO *************/