[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--