[Bf-committers] Face union mesh function write
Spectr
bf-committers@blender.org
Sat, 24 Jan 2004 19:00:43 +0200
This is a multi-part message in MIME format.
--------------020203020508080206010303
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Rob Haarsma wrote:
> Your union_mesh function looks very interesting, it reminds me of the
> Clay modeler.
> I'd like to add this function to Tuhopuu so it can be evaluated by
> everyone, but may I
> ask you to clean it up a little ?
>
> My (windows) compiler chokes when variables are declared between
> statements...
> To get it working i had to move all declarations to the top of the
> function, or after an
> opening bracket.
Yes, i complete this function, and make clean code.
Function in attachment file.
Spectr
--------------020203020508080206010303
Content-Type: text/plain;
name="editmesh.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="editmesh.c"
/* this function find next pair of faces with vertex */
int union_mesh_next_pair(EditVert **ev, EditEdge **eed, EditVlak **evl_1, EditVlak **evl_2) {
EditVlak *evl;
EditVlak *evl1 = NULL;
EditVlak *evl2 = NULL;
int count = 0;
int flag = 0;
int i, j, k;
int edge_flag = 0;
/* find pair on new faces, if exist */
evl=G.edvl.first;
while(evl){
if(evl == *evl_1 || evl == *evl_2) {
evl=evl->next;
continue;
}
if(evl->v1 == *ev) { flag = 1; }
else if(evl->v2 == *ev) { flag = 1; }
else if(evl->v3 == *ev) { flag = 1; }
else if(evl->v4 == *ev) { flag = 1; }
if(flag) {
evl2 = evl1;
evl1 = evl;
count++;
flag = 0;
}
evl=evl->next;
}
if(count != 2)
return 1;
/* find general edge if exist */
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
if((&evl1->e1)[i] && (&evl2->e1)[j] && (&evl1->e1)[i] == (&evl2->e1)[j]) {
*eed = (&evl1->e1)[i];
for(k = 0; k < 4; k++) {
if(*eed == (&((*evl_1)->e1))[k] || *eed == (&((*evl_2)->e1))[k]) {
edge_flag = 1;
break;
}
}
if(edge_flag) {
edge_flag = 0;
continue;
}
/* and get next vertice for next iteration */
if((*eed)->v1 == *ev) {
*ev = (*eed)->v2;
*evl_1 = evl1;
*evl_2 = evl2;
return 0;
}
if((*eed)->v2 == *ev) {
*ev = (*eed)->v1;
*evl_1 = evl1;
*evl_2 = evl2;
return 0;
}
}
/* last iteration */
return 1;
}
/* this function convert two adjustment faces into one (with support loop mode)
with save UV, material, vertex color and other propertyes
and remove 'garbage' faces, edges and vertices after convertion
*/
void union_mesh()
{
#define _UNION_MESH_RETURN \
{\
free(eed_); \
free(evl_1); \
free(evl_2); \
countall(); \
addqueue(curarea->win, REDRAW, 1); \
return; \
}
int mode = 0;
int qual_old = 2; /* set: 1, if start vith SHIFT+KEY, */
/* 2, if start vith CTRL+KEY, */
/* 4, if start vith ALT+KEY, */
int need_change = 1;
char *hm_m[] = {
"Mode: loop (SHIFT), tt->t (CTRL), qt->t (ALT); LMB to confirm, RMB to cancel",
"Mode: single (SHIFT), tt->t (CTRL), qt->t (ALT); LMB to confirm, RMB to cancel",
"Mode: loop (SHIFT), tt->q (CTRL), qt->t (ALT); LMB to confirm, RMB to cancel",
"Mode: single (SHIFT), tt->q (CTRL), qt->t (ALT); LMB to confirm, RMB to cancel",
"Mode: loop (SHIFT), tt->t (CTRL), qt->q (ALT); LMB to confirm, RMB to cancel",
"Mode: single (SHIFT), tt->t (CTRL), qt->q (ALT); LMB to confirm, RMB to cancel",
"Mode: loop (SHIFT), tt->q (CTRL), qt->q (ALT); LMB to confirm, RMB to cancel",
"Mode: single (SHIFT), tt->q (CTRL), qt->q (ALT); LMB to confirm, RMB to cancel"
};
char *hm = hm_m[mode];
EditEdge *eed, *eed_prev;
EditVlak *evl;
EditVlak *ev_0, *ev_1;
int l=0;
eed_prev=NULL;
int mousemove=1;
short event=0;
unsigned short val;
int process_ok=0;
int i, j, k;
int count;
int flag;
/* create new faces */
int v_p[5]; /* index of vertice */
int v_i[5]; /* index of vlak for vertice */
int v_size;
int new_vlak_quad = 0;
EditVlak *e[2];
EditVlak *new_vlak = NULL;
/* create new faces - end*/
float n1[3], n2[3];
float len_1, len_2;
EditEdge **edges = NULL;
int edges_size;
EditVert **vertices = NULL;
int vertices_size;
ListBase *link;
ScrArea *sa = NULL;
EditVlak *evl__;
/* arrays for selected faces and edges */
EditEdge **eed_ = NULL;
int eed_size = 0;
EditVlak **evl_1 = NULL;
EditVlak **evl_2 = NULL;
int evl_size = 0;
int evl_repeat_index=0;
/* calculate size for arrays */
int size=0;
evl=G.edvl.first;
while(evl) {
evl=evl->next;
size++;
}
size++;
size/=2;
/* prepare arrays for selected faces and edges */
eed_ = malloc(sizeof(EditEdge *)*size);
evl_1 = malloc(sizeof(EditVlak *)*(size+1));
evl_2 = malloc(sizeof(EditVlak *)*(size+1));
if ((G.obedit==0) || (G.edvl.first==0)) _UNION_MESH_RETURN
headerprint(hm);
screen_swapbuffers();
while(mousemove) {
/* uses callback mechanism to draw it all in current area */
scrarea_do_windraw(curarea);
/* do your stuff */
eed= findnearestedge();
if(!eed && eed != eed_prev) {
headerprint(hm);
/* this also verifies other area/windows for clean swap */
screen_swapbuffers();
}
if(eed) {
if(eed != eed_prev)
need_change = 1;
/* get new edge list if really needed */
if(need_change) {
count = 0;
flag = 0;
ev_0 = NULL;
ev_1 = NULL;
evl=G.edvl.first;
while(evl){
for(l=0; l<4; l++)
if((&evl->e1)[l] == eed)
flag = 1;
if(flag) {
ev_1 = ev_0;
ev_0 = evl;
count++;
flag = 0;
}
evl=evl->next;
}
if(count == 2) {
process_ok = 1;
eed_size = 1;
evl_size = 1;
eed_[0] = eed;
evl_1[0] = ev_0;
evl_2[0] = ev_1;
if(!(mode & 0x01)) {
EditVert *ev;
EditEdge *ed = eed;
ev = eed_[0]->v1;
while(!union_mesh_next_pair(&ev, &ed, &ev_0, &ev_1)) {
flag = 0;
for(l = 0; l < eed_size; l++)
if(eed_[l] == ed) {
flag = 1;
break;
}
if(flag)
break;
eed_[eed_size] = ed;
evl_1[evl_size] = ev_0;
evl_2[evl_size] = ev_1;
eed_size++;
evl_size++;
}
evl_repeat_index = evl_size;
ev = eed_[0]->v2;
ev_0 = evl_1[0];
ev_1 = evl_2[0];
while(!union_mesh_next_pair(&ev, &ed, &ev_0, &ev_1)) {
flag = 0;
for(l = 0; l < eed_size; l++)
if(eed_[l] == ed) {
flag = 1;
break;
}
if(flag)
break;
eed_[eed_size] = ed;
evl_1[evl_size] = ev_0;
evl_2[evl_size] = ev_1;
eed_size++;
evl_size++;
}
}
}
else process_ok = 0;
}
/* draw highlighted edge */
/* set window matrix to perspective, default an area returns with buttons transform */
persp(PERSP_VIEW);
/* make a copy, for safety */
glPushMatrix();
/* multiply with the object transformation */
mymultmatrix(G.obedit->obmat);
/* draw */
if(!process_ok) {
glColor3ub(231, 15, 15);
glBegin(GL_LINES);
glVertex3fv(eed->v1->co);
glVertex3fv(eed->v2->co);
glEnd();
}
else {
glColor3ub(255, 255, 0);
glBegin(GL_LINES);
for(i=0; i < eed_size; i++) {
glVertex3fv(eed_[i]->v1->co);
glVertex3fv(eed_[i]->v2->co);
}
glEnd();
}
/* restore matrix transform */
glPopMatrix();
headerprint(hm);
/* this also verifies other area/windows for clean swap */
screen_swapbuffers();
}
eed_prev = eed;
/* testing for user input... */
while(!qtest())
/* sleep 0.05 second to prevent overload in this poor loop */
PIL_sleep_ms(50);
while(qtest()) {
event= extern_qread(&val); /* extern_qread stores important events for the mainloop to handle */
/* val==0 on key-release event */
if(event==RIGHTMOUSE || event==LEFTMOUSE || event==ESCKEY || event==RETKEY)
mousemove = 0;
if((event == LEFTMOUSE || event == RETKEY) && !process_ok)
mousemove = 1;
if(!(qual_old & 0x01) && (G.qual & LR_SHIFTKEY)) {
if(mode & 0x01) mode ^= 0x01;
else mode |= 0x01;
need_change = 1;
}
if(!(qual_old & 0x02) && (G.qual & LR_CTRLKEY)) {
if(mode & 0x02) mode ^= 0x02;
else mode |= 0x02;
}
if(!(qual_old & 0x04) && (G.qual & LR_ALTKEY)) {
if(mode & 0x04) mode ^= 0x04;
else mode |= 0x04;
}
if(G.qual & LR_SHIFTKEY) qual_old |= 0x01;
else qual_old ^= 0x01;
if(G.qual & LR_CTRLKEY) qual_old |= 0x02;
else qual_old ^= 0x02;
if(G.qual & LR_ALTKEY) qual_old |= 0x04;
else qual_old ^= 0x04;
hm = hm_m[mode];
}
}
if(event==ESCKEY || event==RIGHTMOUSE)
_UNION_MESH_RETURN
if(event!=LEFTMOUSE && event!=RETKEY)
_UNION_MESH_RETURN
if(!eed || !process_ok)
_UNION_MESH_RETURN
undo_push_mesh("FaceUnion");
vertices = malloc(sizeof(EditVert *)*((evl_size + 1) * 3));
vertices_size = 0;
edges = malloc(sizeof(EditEdge *)*(evl_size * 5 + 2));
edges_size = 0;
/* create new faces */
for(i = 0; i < evl_size; i++) {
v_size = 0;
e[0] = evl_1[i];
e[1] = evl_2[i];
new_vlak = NULL;
/* get edges and vertices from converted faces */
for(j = 0; j < 2; j++) {
for(k = 0; k < 4; k++) {
/* edges */
if((&e[j]->e1)[k] != NULL) {
flag = 0;
for(l = 0; l < edges_size; l++) {
if(edges[l] == (&e[j]->e1)[k]) {
flag = 1;
break;
}
}
if(flag == 0) {
edges[edges_size] = (&e[j]->e1)[k];
edges_size++;
}
}
/* vertices */
if((&e[j]->e1)[k] != NULL) {
flag = 0;
for(l = 0; l < vertices_size; l++) {
if(vertices[l] == (&e[j]->v1)[k]) {
flag = 1;
break;
}
}
if(flag == 0) {
vertices[vertices_size] = (&e[j]->v1)[k];
vertices_size++;
}
}
}
}
/* convert two quad faces to quad face */
if(e[0]->v4 != NULL && e[1]->v4 != NULL) {
/* get vertices */
for(j = 0; j < 4; j++)
for(k = 0; k < 2; k++)
if((&e[k]->v1)[j] != eed_[i]->v1 && (&e[k]->v1)[j] != eed_[i]->v2) {
v_p[v_size] = j;
v_i[v_size] = k;
v_size++;
}
new_vlak_quad = 1;
}
/* convert two triangle faces to one face with current mode */
else if(e[0]->v4 == NULL && e[1]->v4 == NULL) {
/* convert two triangles into one triangle */
for(j = 0; j < 3; j++)
for(k = 0; k < 2; k++)
if((&e[k]->v1)[j] != eed_[i]->v1 && (&e[k]->v1)[j] != eed_[i]->v2) {
v_p[v_size] = j;
v_i[v_size] = k;
v_size++;
}
for(j = 0; j < 3; j++)
if((&e[0]->v1)[j] == eed_[i]->v1 || (&e[0]->v1)[j] == eed_[i]->v2) {
v_p[v_size] = j;
v_i[v_size] = 0;
v_size++;
}
/* create quad face */
if(mode & 0x02) {
new_vlak_quad = 1;
}
/* create triangle face */
else {
len_1 = DistVL2Dfl((&e[v_i[0]]->v1)[v_p[0]]->co, (&e[v_i[1]]->v1)[v_p[1]]->co, (&e[v_i[2]]->v1)[v_p[2]]->co);
len_2 = DistVL2Dfl((&e[v_i[0]]->v1)[v_p[0]]->co, (&e[v_i[1]]->v1)[v_p[1]]->co, (&e[v_i[3]]->v1)[v_p[3]]->co);
if(len_2 > len_1) {
v_p[2] = v_p[3];
v_i[2] = v_i[3];
}
new_vlak_quad = 0;
}
}
/* convert triangle and quad faces to one face with current mode */
else {
if(evl_1[i]->v4 == NULL && evl_2[i]->v4 != NULL) {
e[0] = evl_2[i];
e[1] = evl_1[i];
}
/* e[0] is quad face, e[1] is triangle face */
if(mode & 0x04) {
for(j = 0; j < 4; j++) v_i[j] = 0;
v_i[4] = 1;
for(j = 0; j < 4; j++) {
if(((&e[0]->e1)[j]->v1 == eed_[i]->v1 || (&e[0]->e1)[j]->v1 == eed_[i]->v2) && (&e[0]->e1)[j]->v2 != eed_[i]->v1 && (&e[0]->e1)[j]->v2 != eed_[i]->v2) {
for(k = 0; k < 4; k++) {
if((&e[0]->v1)[k] == (&e[0]->e1)[j]->v2) {
v_p[v_size] = k;
v_size++;
break;
}
}
for(k = 0; k < 4; k++) {
if((&e[0]->v1)[k] == (&e[0]->e1)[j]->v1) {
v_p[v_size] = k;
v_size++;
break;
}
}
}
if(((&e[0]->e1)[j]->v2 == eed_[i]->v1 || (&e[0]->e1)[j]->v2 == eed_[i]->v2) && (&e[0]->e1)[j]->v1 != eed_[i]->v1 && (&e[0]->e1)[j]->v1 != eed_[i]->v2) {
for(k = 0; k < 4; k++) {
if((&e[0]->v1)[k] == (&e[0]->e1)[j]->v1) {
v_p[v_size] = k;
v_size++;
break;
}
}
for(k = 0; k < 4; k++) {
if((&e[0]->v1)[k] == (&e[0]->e1)[j]->v2) {
v_p[v_size] = k;
v_size++;
break;
}
}
}
}
for(j = 0; j < 3; j++) {
if((&e[1]->v1)[j] != eed_[i]->v1 && (&e[1]->v1)[j] != eed_[i]->v2) {
v_p[4] = j;
break;
}
}
/* remove one vertice */
len_1 = DistVL2Dfl((&e[v_i[0]]->v1)[v_p[0]]->co, (&e[v_i[4]]->v1)[v_p[4]]->co, (&e[v_i[1]]->v1)[v_p[1]]->co);
len_2 = DistVL2Dfl((&e[v_i[2]]->v1)[v_p[2]]->co, (&e[v_i[4]]->v1)[v_p[4]]->co, (&e[v_i[3]]->v1)[v_p[3]]->co);
if(len_1 > len_2) {
v_p[3] = v_p[4];
v_i[3] = v_i[4];
}
else {
v_p[1] = v_p[4];
v_i[1] = v_i[4];
}
new_vlak_quad = 1;
}
else {
for(j = 0; j < 4; j++)
if((&e[0]->v1)[j] != eed_[i]->v1 && (&e[0]->v1)[j] != eed_[i]->v2) {
v_p[v_size] = j;
v_i[v_size] = 0;
v_size++;
}
for(j = 0; j < 3; j++)
if((&e[1]->v1)[j] != eed_[i]->v1 && (&e[1]->v1)[j] != eed_[i]->v2) {
v_p[v_size] = j;
v_i[v_size] = 1;
v_size++;
}
new_vlak_quad = 0;
}
}
if(new_vlak_quad) {
/* swap two last vertices if incorrect vectors */
CalcNormFloat((&e[v_i[0]]->v1)[v_p[0]]->co, (&e[v_i[1]]->v1)[v_p[1]]->co, (&e[v_i[2]]->v1)[v_p[2]]->co, n1);
CalcNormFloat((&e[v_i[2]]->v1)[v_p[2]]->co, (&e[v_i[3]]->v1)[v_p[3]]->co, (&e[v_i[0]]->v1)[v_p[0]]->co, n2);
if((n1[0] - n2[0])*(n1[0] - n2[0]) + (n1[1] - n2[1])*(n1[1] - n2[1]) + (n1[2] - n2[2])*(n1[2] - n2[2]) > 2) {
j = v_p[1]; v_p[1] = v_p[2]; v_p[2] = j;
j = v_i[1]; v_i[1] = v_i[2]; v_i[2] = j;
}
CalcNormFloat((&e[v_i[0]]->v1)[v_p[0]]->co, (&e[v_i[1]]->v1)[v_p[1]]->co, (&e[v_i[2]]->v1)[v_p[2]]->co, n1);
CalcNormFloat((&e[v_i[1]]->v1)[v_p[1]]->co, (&e[v_i[2]]->v1)[v_p[2]]->co, (&e[v_i[3]]->v1)[v_p[3]]->co, n2);
if((n1[0] - n2[0])*(n1[0] - n2[0]) + (n1[1] - n2[1])*(n1[1] - n2[1]) + (n1[2] - n2[2])*(n1[2] - n2[2]) > 2) {
j = v_p[3]; v_p[3] = v_p[2]; v_p[2] = j;
j = v_i[3]; v_i[3] = v_i[2]; v_i[2] = j;
}
/* create new face with vertices and correct data from old two faces */
new_vlak = addvlaklist((&e[v_i[0]]->v1)[v_p[0]], (&e[v_i[1]]->v1)[v_p[1]], (&e[v_i[2]]->v1)[v_p[2]], (&e[v_i[3]]->v1)[v_p[3]], e[0]);
}
else {
new_vlak = addvlaklist((&e[v_i[0]]->v1)[v_p[0]], (&e[v_i[1]]->v1)[v_p[1]], (&e[v_i[2]]->v1)[v_p[2]], NULL, e[0]);
}
if(new_vlak != NULL) {
new_vlak->mat_nr = e[0]->mat_nr;
new_vlak->flag = e[0]->flag;
new_vlak->tf = e[0]->tf;
for(j = 0; j < 4; j++) {
if((&new_vlak->v1)[j] == NULL)
break;
new_vlak->tf.uv[j][0] = e[v_i[j]]->tf.uv[v_p[j]][0];
new_vlak->tf.uv[j][1] = e[v_i[j]]->tf.uv[v_p[j]][1];
new_vlak->tf.col[j] = e[v_i[j]]->tf.col[v_p[j]];
}
/* reverse normals if needed */
CalcNormFloat((&new_vlak->v1)[0]->co, (&new_vlak->v1)[1]->co, (&new_vlak->v1)[2]->co, n1);
CalcNormFloat((&e[0]->v1)[0]->co, (&e[0]->v1)[1]->co, (&e[0]->v1)[2]->co, n2);
if((n1[0] - n2[0])*(n1[0] - n2[0]) + (n1[1] - n2[1])*(n1[1] - n2[1]) + (n1[2] - n2[2])*(n1[2] - n2[2]) > 2) {
flipvlak(new_vlak);
}
}
}
link = &G.edvl;
/* delete "garbage" - selected faces and vertices, edges after convertion*/
/* erase faces */
for(i=0; i < evl_size; i++) {
BLI_remlink(link, evl_1[i]);
freevlak(evl_1[i]);
BLI_remlink(link, evl_2[i]);
freevlak(evl_2[i]);
}
countall();
/* erase edges */
for(i = 0; i < edges_size; i++) {
flag = 0;
evl__=G.edvl.first;
while(evl__){
for(j = 0; j < 4; j++) {
if((&evl__->e1)[j] == NULL)
break;
if((&evl__->e1)[j] == edges[i]) {
flag = 1;
break;
}
}
if(flag == 1)
break;
evl__=evl__->next;
}
if(flag == 0) {
remedge(edges[i]);
free(edges[i]);
}
}
free(edges);
/* erase vertices */
for(i = 0; i < vertices_size; i++) {
flag = 0;
evl__=G.edvl.first;
while(evl__){
for(j = 0; j < 4; j++) {
if((&evl__->v1)[j] == NULL)
break;
if((&evl__->v1)[j] == vertices[i]) {
flag = 1;
break;
}
}
if(flag == 1)
break;
evl__=evl__->next;
}
if(flag == 0) {
BLI_remlink(&G.edve, vertices[i]);
free_editvert(vertices[i]);
}
}
free(vertices);
countall();
/* redraw all 3D windows */
sa = G.curscreen->areabase.first;
while(sa) {
if(sa->spacetype==SPACE_VIEW3D)
addqueue(sa->win, REDRAW, 0);
sa=sa->next;
}
_UNION_MESH_RETURN
#undef _UNION_MESH_RETURN
}
--------------020203020508080206010303--