[Bf-committers] Face union mesh function write

Spectr bf-committers@blender.org
Wed, 21 Jan 2004 18:06:15 +0200


This is a multi-part message in MIME format.
--------------050503080007070308000609
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Hi!
Sorry for my bad english, and this is my first post in this mail list.
I write function - in attach two source file from 
CVS/bf-blender/blender/source/blender/src with changes for add this function
in file space.c i add activation over CTRL+V key combination, in 
editmesh.c - source of this function.

This function is union_mesh. I write this for convert two adjacent faces 
in mesh in one with save UV, material and vertex color.
For what this function? First, for create from one mesh object model 
misc object with various LOD, and second - for example, fix mesh after 
boolean operation (in this time, this operation create many faces for 
resulting object).
This function have 3 mode, with toggle keys:
SHIFT - loop or single selection;
CTRL - convert adjacent triangle and quad into: triangle, or quad;
ALT - convert adjacent two quad into: triangle, or quad.

In this time i fix remove garbage vertex and edges after convert two 
faces into one.

Please, try this function, and comment it.

Spectr

--------------050503080007070308000609
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;

	/* 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 */
	int i, j, k;
	int edge_flag = 0;
	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 is a template function to demonstrate a loop with drawing...
   it is a temporal mode, so use with wisdom! if you can avoid, always better. (ton)
*/

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;

	// 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 //
	EditEdge **eed_ = malloc(sizeof(EditEdge *)*size);
	int eed_size = 0;
	EditVlak **evl_1 = malloc(sizeof(EditVlak *)*(size+1));
	EditVlak **evl_2 = malloc(sizeof(EditVlak *)*(size+1));
	int evl_size = 0;
	int evl_repeat_index=0;
	
	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) {
				int count = 0;
				int 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;
						int flag;
						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(val && event!=MOUSEY && event!=MOUSEX)
			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");
	//------------------------------------------------------------------------------------
	// create new faces
	int v_p[5]; // index of vertice
	int v_i[5]; // index of vlak for vertice
	int v_size;
	EditVlak *e[2];
	EditVlak *new_vlak = NULL;
	for(i = 0; i < evl_size; i++) {
		v_size = 0;
		e[0] = evl_1[i];
		e[1] = evl_2[i];
		new_vlak = NULL;
		float n1[3], n2[3];
		// 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++;
					}
			// 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]);
		}
		// 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) {
				// 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]);
			}
			// create triangle face
			else {
				float len_1, len_2;
				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 = 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]);
			}
		}
		// 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
				float len_1, len_2;
				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];
				}
				// 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;
				}
				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 {
				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 = 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);
			}
		}
	}
	
	//------------------------------------------------------------------------------------
	// delete selected faces and edges
	
	EditEdge **edges = malloc(sizeof(EditEdge *)*(evl_size*2 + 2));
	int edges_size = 0;
	ListBase *link = &G.edvl;
	if(evl_repeat_index >= evl_size - 1 || evl_repeat_index == 0)
		evl_repeat_index *= 2;
	evl_repeat_index--;
	if(evl_size > 1) {
		evl_1[evl_size] = evl_1[0];
		evl_2[evl_size] = evl_2[0];
		int it_count = evl_size - 1;
		if(evl_size > 2)
			it_count = evl_size;
		for(l=0; l < it_count; l++) {
			if(l == evl_repeat_index) {
				evl_1[0] = evl_1[l];
				evl_2[0] = evl_2[l];
				evl_1[l] = evl_1[evl_size];
				evl_2[l] = evl_2[evl_size];
			}
			for(i=0; i<4; i++)
				for(j=0; j<4; j++) {
					if((&evl_1[l]->e1)[i] == (&evl_1[l+1]->e1)[j])
						if((&evl_1[l]->e1)[i]) {
							edges[edges_size] = (&evl_1[l]->e1)[i];
							edges_size++;
						}
					if((&evl_1[l]->e1)[i] == (&evl_2[l+1]->e1)[j])
						if((&evl_1[l]->e1)[i]) {
							edges[edges_size] = (&evl_1[l]->e1)[i];
							edges_size++;
						}
					if((&evl_2[l]->e1)[i] == (&evl_1[l+1]->e1)[j])
						if((&evl_2[l]->e1)[i]) {
							edges[edges_size] = (&evl_2[l]->e1)[i];
							edges_size++;
						}
					if((&evl_2[l]->e1)[i] == (&evl_2[l+1]->e1)[j])
						if((&evl_2[l]->e1)[i]) {
							edges[edges_size] = (&evl_2[l]->e1)[i];
							edges_size++;
						}
				}
		}
	}
	for(l=0; l < evl_size; l++) {
		BLI_remlink(link, evl_1[l]);
		freevlak(evl_1[l]);
		BLI_remlink(link, evl_2[l]);
		freevlak(evl_2[l]);
	}
	for(l=0; l < eed_size; l++) {
		remedge(eed_[l]);
		free(eed_[l]);
	}
	for(l=0; l < edges_size; l++) {
		remedge(edges[l]);
		free(edges[l]);
	}
	free(edges);
	//------------------------------------------------------------------------------------
	// redraw all 3D windows
	ScrArea *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
}

//----------------------------------------------------------------------------------------------------

--------------050503080007070308000609
Content-Type: text/plain;
 name="space.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="space.c"

void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
{
			.
			.
			.
			case VKEY:
				ob= OBACT;
				if((G.qual==LR_SHIFTKEY)) {
					if ((G.obedit) && G.obedit->type==OB_MESH) {
						align_view_to_selected(v3d);
					}
					else if (G.f & G_FACESELECT) {
						align_view_to_selected(v3d);
					}
				}
				else if(G.qual==LR_ALTKEY)
					image_aspect();
				else if(G.qual == LR_CTRLKEY && G.obedit) {
					union_mesh();
					break;
				}
				else if(G.qual == LR_CTRLKEY) {
					union_mesh();
					break;
				}
				else if (G.qual==0){
					if(G.obedit) {
						if(G.obedit->type==OB_CURVE) {
							sethandlesNurb(2);
							makeDispList(G.obedit);
							allqueue(REDRAWVIEW3D, 0);
						}
					}
					else if(ob && ob->type == OB_MESH) 
						set_vpaint();
				}
				break;
			.
			.
			.
}
--------------050503080007070308000609--