1 #include "xr_mesh_builder.h"
2 #include "xr_object.h"
3 #include "xr_utils.h"
4 #include "xr_mesh_utils.h"
5 
6 using namespace xray_re;
7 
set(uint32_t signature,uint32_t x0,uint32_t x1,uint32_t x2)8 xr_mesh_builder::b_face& xr_mesh_builder::b_face::set(uint32_t signature, uint32_t x0, uint32_t x1, uint32_t x2)
9 {
10 	xr_assert(signature);
11 	if (signature & xr_vbuf::S_POINTS) {
12 		v0 = x0;
13 		v1 = x1;
14 		v2 = x2;
15 	}
16 	if (signature & xr_vbuf::S_NORMALS) {
17 		n0 = x0;
18 		n1 = x1;
19 		n2 = x2;
20 	}
21 	if (signature & xr_vbuf::S_TEXCOORDS) {
22 		tc0 = x0;
23 		tc1 = x1;
24 		tc2 = x2;
25 	}
26 	return *this;
27 }
28 
is_duplicate(const b_face & face) const29 bool xr_mesh_builder::b_face::is_duplicate(const b_face& face) const
30 {
31 	for (uint_fast32_t i0 = 0; i0 != 3; ++i0) {
32 		if (v[i0] != face.v0)
33 			continue;
34 		uint_fast32_t i1 = (1 << i0) & 3;
35 		uint_fast32_t i2 = (1 << i1) & 3;
36 		return v[i1] == face.v1 && v[i2] == face.v2 &&
37 				sector == face.sector && surface == face.surface &&
38 				n[i0] == face.n0 && n[i1] == face.n1 && n[i2] == face.n2 &&
39 				tc[i0] == face.tc0 && tc[i1] == face.tc1 && tc[i2] == face.tc2;
40 	}
41 	return false;
42 }
43 
is_back(const b_face & face,const std::vector<fvector3> & normals,float normal_tolerance) const44 bool xr_mesh_builder::b_face::is_back(const b_face& face,
45 		const std::vector<fvector3>& normals, float normal_tolerance) const
46 {
47 	for (uint_fast32_t i0 = 0; i0 != 3; ++i0) {
48 		if (v[i0] != face.v0)
49 			continue;
50 		uint_fast32_t i1 = (1 << i0) & 3;
51 		uint_fast32_t i2 = (1 << i1) & 3;
52 		return v[i1] == face.v2 && v[i2] == face.v1 &&
53 				sector == face.sector && surface == face.surface &&
54 				tc[i0] == face.tc0 && tc[i1] == face.tc2 && tc[i2] == face.tc1 &&
55 				normals[n[i0]].inverted(normals[face.n0], normal_tolerance) &&
56 				normals[n[i1]].inverted(normals[face.n2], normal_tolerance) &&
57 				normals[n[i2]].inverted(normals[face.n1], normal_tolerance);
58 	}
59 	return false;
60 }
61 
is_same_layer(uint_fast32_t v0,uint_fast32_t v1) const62 bool xr_mesh_builder::b_face::is_same_layer(uint_fast32_t v0, uint_fast32_t v1) const
63 {
64 	return ((1u << local_vert_idx(v0)) & 3) != local_vert_idx(v1);
65 }
66 
is_edge_smooth(const b_face & face,uint_fast32_t v0,uint_fast32_t v1) const67 bool xr_mesh_builder::b_face::is_edge_smooth(const b_face& face, uint_fast32_t v0, uint_fast32_t v1) const
68 {
69 	uint_fast32_t i0 = local_vert_idx(v0);
70 	uint_fast32_t i1 = local_vert_idx(v1);
71 	uint_fast32_t j0 = face.local_vert_idx(v0);
72 	uint_fast32_t j1 = face.local_vert_idx(v1);
73 	return n[i0] == face.n[j0] && n[i1] == face.n[j1] &&
74 			v[3 - i0 - i1] != face.v[3 - j0 - j1];
75 }
76 
77 ////////////////////////////////////////////////////////////////////////////////
78 
xr_mesh_builder()79 xr_mesh_builder::xr_mesh_builder() {}
80 
~xr_mesh_builder()81 xr_mesh_builder::~xr_mesh_builder() {}
82 
set_tc_fix(bool tc_fix)83 void xr_mesh_builder::set_tc_fix(bool tc_fix) { m_vb.set_tc_fix(tc_fix); }
84 
85 template<typename T> struct xr_mesh_builder::b_proxy::less {
86 	const T* data;
lessxr_mesh_builder::b_proxy::less87 	explicit less(const T* _data): data(_data) {}
operator ()xr_mesh_builder::b_proxy::less88 	inline bool operator()(const b_proxy& l, const b_proxy& r) const {
89 		return data[l.index] < data[r.index];
90 	}
91 };
92 
93 template<typename T1, typename T2> struct xr_mesh_builder::b_proxy::less2 {
94 	const T1* data1;
95 	const T2* data2;
less2xr_mesh_builder::b_proxy::less296 	explicit less2(const T1* _data1, const T2* _data2): data1(_data1), data2(_data2) {}
operator ()xr_mesh_builder::b_proxy::less297 	inline bool operator()(const b_proxy& l, const b_proxy& r) const {
98 		return data1[l.index] < data1[r.index] ||
99 				(data1[l.index] == data1[r.index] && data2[l.index] < data2[r.index]);
100 	}
101 };
102 
prepare(uint32_t signature,size_t num_vertices,size_t num_indices)103 void xr_mesh_builder::prepare(uint32_t signature, size_t num_vertices, size_t num_indices)
104 {
105 	m_vb.set_signature(signature);
106 	m_vb.reserve(num_vertices);
107 	m_refs.reserve(num_vertices);
108 	m_faces.reserve(num_indices/3);
109 }
110 
push(const xr_vbuf & vb,const xr_ibuf & ib,uint16_t texture,uint16_t eshader)111 void xr_mesh_builder::push(const xr_vbuf& vb, const xr_ibuf& ib, uint16_t texture, uint16_t eshader)
112 {
113 	b_face face_template;
114 	face_template.surface.set(texture, eshader);
115 	if (vb.has_lightmaps())
116 		face_template.surface.flags |= RSF_LIGHTMAP;
117 	__push(vb, ib, 0, face_template, PF_DEFAULT);
118 }
119 
__push(const xr_vbuf & vb,const xr_ibuf & ib,const fmatrix * xform,const b_face & face_template,unsigned pflags)120 void xr_mesh_builder::__push(const xr_vbuf& vb, const xr_ibuf& ib, const fmatrix* xform,
121 		const b_face& face_template, unsigned pflags)
122 {
123 	size_t num_new_faces = 0;
124 	uint32_t signature = m_vb.signature(), vb_offset = uint32_t(m_vb.size() & UINT32_MAX);
125 	b_face face(face_template);
126 	for (size_t i = 0, num_indices = ib.size(); i != num_indices; i += 3) {
127 		uint32_t v0 = ib[i + 0];
128 		uint32_t v1 = ib[i + 1];
129 		const fvector3& p0 = vb.p(v0);
130 		const fvector3& p1 = vb.p(v1);
131 		if (p0 == p1)
132 			continue;
133 		uint32_t v2 = ib[i + 2];
134 		const fvector3& p2 = vb.p(v2);
135 		if (p1 == p2 || p2 == p0)
136 			continue;
137 
138 		float area = calc_area(p0, p1, p2);
139 		if (area <= 1e-5f) {
140 			m_build_err.zero_area_face(p0, p1, p2);
141 			if (pflags & PF_REMOVE_ZERO_FACE)
142 				continue;
143 		}
144 		float perim = calc_perimeter(vb.tc(v0), vb.tc(v1), vb.tc(v2));
145 		if (perim <= 1/8192.f) {
146 			m_build_err.zero_uv_area_face(p0, p1, p2);
147 			if (pflags & PF_REMOVE_ZERO_UV_FACE)
148 				continue;
149 		}
150 #if 0
151 		if (vb.has_lightmaps()) {
152 			const fvector2& lm0 = vb.lm(v0);
153 			const fvector2& lm1 = vb.lm(v1);
154 			const fvector2& lm2 = vb.lm(v2);
155 #if 1
156 			fvector3 uv0, uv1, uv2;
157 			uv0.set(lm0.x, 0, lm0.y);
158 			uv1.set(lm1.x, 0, lm1.y);
159 			uv2.set(lm2.x, 0, lm2.y);
160 			float k = calc_area_xz(uv0, uv1, uv2)*1024.f*1024.f/calc_area(p0, p1, p2);
161 			printf("lm_density: %f\n", k);
162 #else
163 			float k01 = lm0.distance(lm1)*1024.f/p0.distance(p1);
164 			float k12 = lm1.distance(lm2)*1024.f/p1.distance(p2);
165 			float k20 = lm2.distance(lm0)*1024.f/p2.distance(p0);
166 //			if (equivalent(k01, 0.f)) {
167 			if (equivalent(k01, 5.f)) {
168 //			if (k01 < 2.f) {
169 				printf("  face: [%f,%f,%f][%f,%f,%f][%f,%f,%f],\n  lm: [%f,%f][%f,%f][%f,%f]\n",
170 						p0.x, p0.y, p0.z, p1.x, p1.y, p1.z, p2.x, p2.y, p2.z,
171 						lm0.x, lm0.y, lm1.x, lm1.y, lm2.x, lm2.y);
172 			}
173 			printf("lm_density: %.2f/%.2f/%.2f\n", k01, k12, k20);
174 #endif
175 		}
176 #endif
177 		m_faces.push_back(face.set(signature, vb_offset + v0, vb_offset + v1, vb_offset + v2));
178 		++num_new_faces;
179 	}
180 	if (num_new_faces) {
181 		for (size_t i = vb.size(); i != 0; --i, ++vb_offset)
182 			m_refs.push_back(b_proxy(vb_offset));
183 		m_vb.push(vb, &ib, xform);
184 	}
185 }
186 
187 template<typename T> void
create_unique_array(b_proxy_vec & refs,std::vector<T> & data,const T * raw_data,uint32_t * mapping)188 xr_mesh_builder::create_unique_array(b_proxy_vec& refs, std::vector<T>& data, const T* raw_data, uint32_t* mapping)
189 {
190 	std::sort(refs.begin(), refs.end(), b_proxy::less<T>(raw_data));
191 	uint32_t index = 0;
192 	for (b_proxy_vec_it it = refs.begin(), end = refs.end(); it != end; ++index) {
193 		const T& value = raw_data[it->index];
194 		data.push_back(value);
195 		mapping[it->index] = index;
196 		while (++it != end && raw_data[it->index] == value)
197 			mapping[it->index] = index;
198 	}
199 }
200 
201 template<typename T1, typename T2> void
create_unique_array2(b_proxy_vec & refs,std::vector<T1> & data1,std::vector<T2> & data2,const T1 * raw_data1,const T2 * raw_data2,uint32_t * mapping)202 xr_mesh_builder::create_unique_array2(b_proxy_vec& refs, std::vector<T1>& data1, std::vector<T2>& data2,
203 		const T1* raw_data1, const T2* raw_data2, uint32_t* mapping)
204 {
205 	std::sort(refs.begin(), refs.end(), b_proxy::less2<T1, T2>(raw_data1, raw_data2));
206 	uint32_t index = 0;
207 	for (b_proxy_vec_it it = refs.begin(), end = refs.end(); it != end; ++index) {
208 		const T1& value1 = raw_data1[it->index];
209 		data1.push_back(value1);
210 		const T2& value2 = raw_data2[it->index];
211 		data2.push_back(value2);
212 		mapping[it->index] = index;
213 		while (++it != end && raw_data1[it->index] == value1 && raw_data2[it->index] == value2)
214 			mapping[it->index] = index;
215 	}
216 }
217 
compact_geometry()218 void xr_mesh_builder::compact_geometry()
219 {
220 	uint32_t* mapping = new uint32_t[m_refs.size()];
221 	if (m_vb.has_influences())
222 		create_unique_array2(m_refs, m_points, m_influences, m_vb.p(), m_vb.w(), mapping);
223 	else
224 		create_unique_array(m_refs, m_points, m_vb.p(), mapping);
225 	for (b_face_vec_it it = m_faces.begin(), end = m_faces.end(); it != end; ++it) {
226 		it->v0 = mapping[it->v0];
227 		it->v1 = mapping[it->v1];
228 		it->v2 = mapping[it->v2];
229 	}
230 	if (m_vb.has_normals()) {
231 		create_unique_array(m_refs, m_normals, m_vb.n(), mapping);
232 		for (b_face_vec_it it = m_faces.begin(), end = m_faces.end(); it != end; ++it) {
233 			it->n0 = mapping[it->n0];
234 			it->n1 = mapping[it->n1];
235 			it->n2 = mapping[it->n2];
236 		}
237 	}
238 	if (m_vb.has_texcoords()) {
239 		create_unique_array(m_refs, m_texcoords, m_vb.tc(), mapping);
240 		for (b_face_vec_it it = m_faces.begin(), end = m_faces.end(); it != end; ++it) {
241 			it->tc0 = mapping[it->tc0];
242 			it->tc1 = mapping[it->tc1];
243 			it->tc2 = mapping[it->tc2];
244 		}
245 	}
246 	delete[] mapping;
247 
248 	m_vb.clear();
249 	b_proxy_vec().swap(m_refs);
250 
251 #if 0
252 	for (b_face_vec_it it = m_faces.begin(), end = m_faces.end(); it != end; ++it) {
253 		fvector3 n1, n2, n3;
254 		uint16_t packed1 = n1.calc_normal(m_points[it->v0], m_points[it->v1], m_points[it->v2]).compress();
255 		uint16_t packed2 = n2.decompress(packed1).compress();
256 		uint16_t packed3 = n3.decompress(packed2).compress();
257 		msg("distance12=%f, distance23=%f", n1.distance(n2), n2.distance(n3));
258 		xr_assert(n1.distance(n2) < 0.3f);
259 	}
260 #endif
261 }
262 
operator ()bad_face_pred263 struct bad_face_pred { bool operator()(const xr_mesh_builder::b_face& face) const { return face.surf_idx == BAD_IDX; }};
264 
remove_duplicate_faces()265 void xr_mesh_builder::remove_duplicate_faces()
266 {
267 	generate_vertex_faces();
268 	for (b_face_vec_it it = m_faces.begin(), end = m_faces.end(); it != end; ++it) {
269 		for (uint_fast32_t next = m_vertex_faces[it->v0]; next != BAD_IDX;) {
270 			b_face* face = &m_faces[next];
271 			if (face > &*it && it->is_duplicate(*face)) {
272 				it->surf_idx = BAD_IDX;
273 				goto skip;
274 			}
275 			next = face->next_face_idx(it->v0);
276 		}
277 skip:;
278 	}
279 	m_faces.erase(std::remove_if(m_faces.begin(), m_faces.end(), bad_face_pred()), m_faces.end());
280 }
281 
282 // FIXME: it should be possible to determine the "right" side in
283 // model (external) OGFs using simple face ordering heuristics.
284 // Not sure for the level (embedded) OGFs though.
remove_back_faces(float normal_tolerance)285 void xr_mesh_builder::remove_back_faces(float normal_tolerance)
286 {
287 	generate_vertex_faces();
288 
289 	size_t num_faces = m_faces.size();
290 
291 	uint32_t* face_backs = new uint32_t[num_faces];
292 	xr_uninitialized_fill_n(face_backs, num_faces, BAD_IDX);
293 	uint32_t face_idx = 0;
294 	for (b_face_vec_cit it = m_faces.begin(), end = m_faces.end();
295 			it != end; ++it, ++face_idx) {
296 		for (uint_fast32_t next = m_vertex_faces[it->v0]; next != BAD_IDX;) {
297 			b_face& face = m_faces[next];
298 			if (it->is_back(face, m_normals, normal_tolerance)) {
299 				face_backs[face_idx] = uint32_t(next & UINT32_MAX);
300 				face_backs[next] = face_idx;
301 				break;
302 			}
303 			next = face.next_face_idx(it->v0);
304 		}
305 	}
306 
307 	create_edges();
308 
309 	std::vector<uint32_t> adjacents;
310 	adjacents.reserve(512);
311 	std::vector<int> sides;
312 	sides.reserve(256);
313 
314 	uint32_t* lgroups = new uint32_t[num_faces];
315 	xr_uninitialized_fill_n(lgroups, num_faces, BAD_IDX);
316 
317 	uint32_t lgroup = 0;
318 	for (size_t k = 0; k != num_faces; ++k) {
319 		if (face_backs[k] == BAD_IDX || lgroups[k] != BAD_IDX)
320 			continue;
321 		int side = 0;
322 		face_idx = uint32_t(k & UINT32_MAX);
323 		lgroups[face_idx] = lgroup;
324 		lgroups[face_backs[face_idx]] = lgroup + 1;
325 		for (;;) {
326 			const b_face& face = m_faces[face_idx];
327 			for (uint_fast32_t i = 3, v0, v1 = face.v0; i != 0; v1 = v0) {
328 				b_edge* edge = find_edge(v0 = face.v[--i], v1);
329 				xr_assert(edge && (v0 == edge->v1 || v1 == edge->v1));
330 				if (edge->size > 4)
331 					continue;
332 				for (uint_fast32_t next = edge->face0; next != BAD_IDX;) {
333 					const b_face& adjacent = m_faces[next];
334 					if (next != face_idx && next != face_backs[face_idx] &&
335 							lgroups[next] == BAD_IDX) {
336 						bool same_layer = adjacent.is_same_layer(v0, v1);
337 						uint_fast32_t next_back = face_backs[next];
338 						if (next_back == BAD_IDX) {
339 							if (edge->size > 3)
340 								break;
341 							if (same_layer)
342 								--side;
343 							else
344 								++side;
345 						} else if (same_layer) {
346 							adjacents.push_back(uint32_t(next & UINT32_MAX));
347 							lgroups[next] = lgroup;
348 							lgroups[next_back] = lgroup + 1;
349 							break;
350 						} else {
351 							adjacents.push_back(uint32_t(next_back & UINT32_MAX));
352 							lgroups[next_back] = lgroup;
353 							lgroups[next] = lgroup + 1;
354 							break;
355 						}
356 					}
357 
358 					// check for endless cycle. It`s in build 2232 l06_rostok
359 					uint_fast32_t temp = adjacent.next_face_idx(v0, v1);
360 					if (next == temp)
361 						break;
362 					next = temp;
363 				}
364 			}
365 			if (adjacents.empty())
366 				break;
367 			face_idx = adjacents.back();
368 			adjacents.pop_back();
369 
370 		}
371 		if (side == 0)
372 			side = -1;
373 		sides.push_back(side);
374 		lgroup += 2;
375 	}
376 
377 	face_idx = 0;
378 	b_face_vec_it last = m_faces.begin();
379 	for (b_face_vec_it it = last, end = m_faces.end(); it != end; ++it, ++face_idx) {
380 		if (face_backs[face_idx] != BAD_IDX) {
381 			int side = sides[(lgroup = lgroups[face_idx])/2];
382 			if (lgroup & 1)
383 				side = -side;
384 			if (side < 0)
385 				it->surface.flags |= RSF_TWO_SIDED;
386 			else
387 				continue;
388 		}
389 		if (last != it)
390 			*last = *it;
391 		++last;
392 	}
393 	m_faces.erase(last, m_faces.end());
394 
395 	delete[] lgroups;
396 	delete[] face_backs;
397 }
398 
generate_vertex_faces()399 void xr_mesh_builder::generate_vertex_faces()
400 {
401 	m_vertex_faces.assign(m_points.size(), BAD_IDX);
402 	uint32_t face_idx = 0;
403 	for (b_face_vec_it it = m_faces.begin(), end = m_faces.end();
404 			it != end; ++it, ++face_idx) {
405 		it->link0 = m_vertex_faces[it->v0];
406 		it->link1 = m_vertex_faces[it->v1];
407 		it->link2 = m_vertex_faces[it->v2];
408 		m_vertex_faces[it->v0] = face_idx;
409 		m_vertex_faces[it->v1] = face_idx;
410 		m_vertex_faces[it->v2] = face_idx;
411 	}
412 }
413 
find_edge(uint_fast32_t v0,uint_fast32_t v1)414 xr_mesh_builder::b_edge* xr_mesh_builder::find_edge(uint_fast32_t v0, uint_fast32_t v1)
415 {
416 	for (uint_fast32_t next = m_vertex_edges[v0]; next != BAD_IDX;) {
417 		b_edge* edge = &m_edges[next];
418 		if (edge->v1 == v1)
419 			return edge;
420 		next = edge->link;
421 	}
422 	for (uint_fast32_t next = m_vertex_edges[v1]; next != BAD_IDX;) {
423 		b_edge* edge = &m_edges[next];
424 		if (edge->v1 == v0)
425 			return edge;
426 		next = edge->link;
427 	}
428 	return 0;
429 }
430 
create_edges(bool calc_smoothness)431 void xr_mesh_builder::create_edges(bool calc_smoothness)
432 {
433 	m_vertex_edges.assign(m_points.size(), BAD_IDX);
434 	m_edges.clear();
435 	m_edges.reserve(m_points.size());
436 	uint32_t face_idx = 0;
437 	for (b_face_vec_it it = m_faces.begin(), end = m_faces.end();
438 			it != end; ++it, ++face_idx) {
439 		for (uint_fast32_t i = 3, v0, v1 = it->v0; i != 0; v1 = v0) {
440 			b_edge* edge = find_edge(v0 = it->v[--i], v1);
441 			if (edge == 0) {
442 				it->link[i] = BAD_IDX;
443 				uint32_t next = m_vertex_edges[v0];
444 				m_vertex_edges[v0] = uint32_t(m_edges.size() & UINT32_MAX);
445 				m_edges.push_back(b_edge(v1, face_idx, next));
446 			} else {
447 				it->link[i] = edge->face0;
448 				if (!calc_smoothness) {
449 					++edge->size;
450 				} else {
451 					edge->smooth = (++edge->size == 2) ?
452 							it->is_edge_smooth(m_faces[edge->face0], v0, v1) : false;
453 				}
454 				edge->face0 = face_idx;
455 			}
456 		}
457 	}
458 }
459 
460 ////////////////////////////////////////////////////////////////////////////////
461 
create_smoothing_groups()462 void xr_mesh_builder::create_smoothing_groups()
463 {
464 	if (m_normals.empty())
465 		return;
466 
467 	create_edges(true);
468 
469 	m_sgroups.assign(m_faces.size(), EMESH_NO_SG);
470 	std::vector<uint32_t> adjacents;
471 	adjacents.reserve(512);
472 	uint32_t sgroup = 0;
473 	for (uint_fast32_t idx = uint32_t(m_faces.size() & UINT32_MAX); idx != 0;) {
474 		if (m_sgroups[--idx] != EMESH_NO_SG)
475 			continue;
476 		uint32_t tag = m_faces[idx].tag;
477 		bool new_sgroup = false;
478 		for (uint_fast32_t face_idx = idx;;) {
479 			const b_face& face = m_faces[face_idx];
480 			for (uint_fast32_t i = 3, v0, v1 = face.v0; i != 0; v1 = v0) {
481 				b_edge* edge = find_edge(v0 = face.v[--i], v1);
482 				xr_assert(edge);
483 				if (!edge->smooth)
484 					continue;
485 				if (!new_sgroup) {
486 					new_sgroup = true;
487 					m_sgroups[face_idx] = sgroup;
488 				}
489 				uint32_t adjacent = (edge->face0 == face_idx) ?
490 						face.link[i] : edge->face0;
491 				if (m_sgroups[adjacent] == EMESH_NO_SG &&
492 						m_faces[adjacent].tag == tag) {
493 					adjacents.push_back(adjacent);
494 					m_sgroups[adjacent] = sgroup;
495 				}
496 			}
497 			if (adjacents.empty())
498 				break;
499 			face_idx = adjacents.back();
500 			adjacents.pop_back();
501 		}
502 		if (new_sgroup)
503 			++sgroup;
504 	}
505 }
506 
operator ()surface_pred507 struct surface_pred { bool operator()(const xr_mesh_builder::b_face* l, const xr_mesh_builder::b_face* r) const {
508 	return l->surface < r->surface;
509 }};
510 
compact_raw_surfaces()511 void xr_mesh_builder::compact_raw_surfaces()
512 {
513 	b_face **refs = new b_face*[m_faces.size()];
514 	b_face **ref = refs;
515 	b_face **refs_end = refs + m_faces.size();
516 	for (b_face_vec_it it = m_faces.begin(), end = m_faces.end(); it != end; ++it)
517 		*ref++ = &*it;
518 	std::sort(refs, refs_end, surface_pred());
519 
520 	uint32_t surf_idx = 0;
521 	for (ref = refs; ref != refs_end; ++surf_idx) {
522 		b_face* face = *ref;
523 		xr_raw_surface surface(face->surface);
524 		m_raw_surfaces.push_back(surface);
525 		face->surf_idx = surf_idx;
526 		face->sgroup = EMESH_NO_SG;
527 		while (++ref != refs_end && (face = *ref)->surface == surface) {
528 			face->surf_idx = surf_idx;
529 			face->sgroup = EMESH_NO_SG;
530 		}
531 	}
532 	delete[] refs;
533 }
534 
create_mappings(lw_face_vec & faces,lw_vmref_vec & vmrefs,xr_vmap_vec & vmaps,const xr_bone_vec & bones) const535 void xr_mesh_builder::create_mappings(lw_face_vec& faces, lw_vmref_vec& vmrefs, xr_vmap_vec& vmaps,
536 		const xr_bone_vec& bones) const
537 {
538 	xr_uv_vmap* uv_vmap = 0;
539 	xr_face_uv_vmap* face_uv_vmap = 0;
540 	uint32_t vert_idx = 0;
541 	for (std::vector<uint32_t>::const_iterator it = m_vertex_faces.begin(),
542 			end = m_vertex_faces.end(); it != end; ++it, ++vert_idx) {
543 		if (*it == BAD_IDX) {
544 			const fvector3& p = m_points[vert_idx];
545 			msg("unused vertex %g,%g,%g", p.x, p.y, p.z);
546 			continue;
547 		}
548 
549 		lw_vmref vmref0;
550 		uint32_t tc0 = BAD_IDX, vmref0_idx = 0;
551 		for (uint32_t face_idx = *it; face_idx != BAD_IDX;) {
552 			const b_face& face = m_faces[face_idx];
553 			if (face_idx == BAD_IDX) {
554 				face_idx = face.next_face_idx(vert_idx);
555 				continue;
556 			}
557 			uint_fast32_t local_idx = face.local_vert_idx(vert_idx);
558 			uint32_t tc = face.tc[local_idx], vmref_idx;
559 			xr_assert(tc != BAD_IDX);
560 			if (tc0 == BAD_IDX) {
561 				if (uv_vmap == 0) {
562 					uv_vmap = new xr_uv_vmap("Texture");
563 					vmaps.push_back(uv_vmap);
564 				}
565 				vmref0.push_back(lw_vmref_entry(0, uv_vmap->add_uv(
566 						m_texcoords[tc0 = tc], vert_idx)));
567 				vmref0_idx = vmref_idx = uint32_t(vmrefs.size() & UINT32_MAX);
568 				vmrefs.push_back(vmref0);
569 			} else if (tc0 == tc) {
570 				vmref_idx = vmref0_idx;
571 			} else {
572 				if (face_uv_vmap == 0) {
573 					face_uv_vmap = new xr_face_uv_vmap("Texture");
574 					vmaps.push_back(face_uv_vmap);
575 				}
576 				lw_vmref vmref;
577 				vmref.push_back(lw_vmref_entry(1, face_uv_vmap->add_uv(
578 						m_texcoords[tc], vert_idx, face_idx)));
579 				vmref_idx = uint32_t(vmrefs.size() & UINT32_MAX);
580 				vmrefs.push_back(vmref);
581 			}
582 			faces[face_idx].ref[local_idx] = vmref_idx;
583 			face_idx = face.link[local_idx];
584 		}
585 	}
586 	// bones.empty() check is required when trying to convert external LOD parts in older builds.
587 	if (!m_influences.empty() && !bones.empty()) {
588 		uint32_t offset = uint32_t(vmaps.size() & UINT32_MAX);
589 		vmaps.resize(offset + bones.size());
590 		lw_vmref_vec weight_vmrefs(m_influences.size());
591 		vert_idx = 0;
592 		for (std::vector<finfluence>::const_iterator it = m_influences.begin(),
593 				end = m_influences.end(); it != end; ++it, ++vert_idx) {
594 			for (finfluence::const_iterator it1 = it->begin(), end1 = it->end();
595 					it1 != end1; ++it1) {
596 				xr_weight_vmap* weight_vmap = static_cast<xr_weight_vmap*>(vmaps.at(offset + it1->bone));
597 				if (weight_vmap == 0) {
598 					vmaps[offset + it1->bone] = weight_vmap =
599 							new xr_weight_vmap(bones.at(it1->bone)->name());
600 				}
601 				uint32_t weight_idx = weight_vmap->add_weight(it1->weight, vert_idx);
602 				xr_assert(!weight_vmrefs[vert_idx].full());
603 				weight_vmrefs[vert_idx].push_back(lw_vmref_entry(offset + it1->bone, weight_idx));
604 			}
605 		}
606 		for (lw_face_vec_it it = faces.begin(), end = faces.end(); it != end; ++it) {
607 			for (uint_fast32_t i = 3; i != 0;) {
608 				lw_vmref& vmref = vmrefs[it->ref[--i]];
609 				if (vmref.size() > 1)
610 					continue;
611 				vmref.append(weight_vmrefs[it->v[i]]);
612 			}
613 		}
614 	}
615 	uint32_t* vmap_remap = new uint32_t[vmaps.size()];
616 	unsigned used = 0;
617 	for (uint_fast32_t i = 0, n = vmaps.size(); i != n; ++i) {
618 		if (i != used)
619 			vmaps[used] = vmaps[i];
620 		vmap_remap[i] = vmaps[i] ? used++ : BAD_IDX;
621 	}
622 	vmaps.resize(used);
623 	for (lw_vmref_vec_it it = vmrefs.begin(), end = vmrefs.end(); it != end; ++it) {
624 		for (lw_vmref::iterator it1 = it->begin(), end1 = it->end(); it1 != end1; ++it1)
625 			it1->vmap = vmap_remap[it1->vmap];
626 	}
627 	delete[] vmap_remap;
628 }
629 
commit(xr_object & object)630 void xr_mesh_builder::commit(xr_object& object)
631 {
632 	compact_raw_surfaces();
633 	m_surfmaps.reserve(m_raw_surfaces.size());
634 	for (xr_raw_surface_vec_it it = m_raw_surfaces.begin(), end = m_raw_surfaces.end();
635 			it != end; ++it) {
636 		xr_surfmap* smap = new xr_surfmap(object.attach(*it));
637 		m_surfmaps.push_back(smap);
638 	}
639 	xr_raw_surface_vec().swap(m_raw_surfaces);
640 
641 	create_smoothing_groups();
642 	std::vector<fvector3>().swap(m_normals);
643 	b_edge_vec().swap(m_edges);
644 	std::vector<uint32_t>().swap(m_vertex_edges);
645 
646 	xr_mesh::m_faces.reserve(m_faces.size());
647 	uint32_t face_idx = 0;
648 	for (b_face_vec_it it = m_faces.begin(), end = m_faces.end();
649 			it != end; ++it, ++face_idx) {
650 		xr_mesh::m_faces.push_back(lw_face(it->v0, it->v1, it->v2));
651 		xr_assert(it->surf_idx != BAD_IDX);
652 		m_surfmaps[it->surf_idx]->faces.push_back(face_idx);
653 	}
654 
655 	generate_vertex_faces();
656 	create_mappings(xr_mesh::m_faces, m_vmrefs, m_vmaps, object.bones());
657 	std::vector<fvector2>().swap(m_texcoords);
658 	std::vector<finfluence>().swap(m_influences);
659 	std::vector<uint32_t>().swap(m_vertex_faces);
660 	b_face_vec().swap(m_faces);
661 
662 	calculate_bbox();
663 
664 	object.meshes().push_back(this);
665 }
666 
remove_empty_surfmaps()667 void xr_mesh_builder::remove_empty_surfmaps()
668 {
669 	xr_surfmap_vec_it last = m_surfmaps.begin();
670 	for (xr_surfmap_vec_it it = last, end = m_surfmaps.end(); it != end; ++it) {
671 		xr_surfmap* smap = *it;
672 		if (smap->faces.empty()) {
673 			delete smap;
674 			continue;
675 		}
676 		if (it != last)
677 			*last = smap;
678 		++last;
679 	}
680 	m_surfmaps.erase(last, m_surfmaps.end());
681 }
682