Line data Source code
1 : /**
2 : * @brief cube object member functions
3 : *
4 : * This file implements the methods applying to the cube object, the individual
5 : * unit which acts as the nodes in a cubeworld octal tree.
6 : */
7 :
8 : #include "../libprimis-headers/cube.h"
9 : #include "../../shared/geomexts.h"
10 :
11 : #include "light.h"
12 : #include "octaworld.h"
13 : #include "raycube.h"
14 : #include "world.h"
15 :
16 : #include "interface/console.h"
17 :
18 : #include "render/octarender.h"
19 : #include "render/renderwindow.h"
20 :
21 : VAR(maxmerge, 0, 6, 12); //max gridpower to remip merge
22 : VAR(minface, 0, 4, 12);
23 :
24 0 : bool touchingface(const cube &c, int orient)
25 : {
26 0 : uint face = c.faces[DIMENSION(orient)];
27 0 : return DIM_COORD(orient) ? (face&0xF0F0F0F0)==0x80808080 : (face&0x0F0F0F0F)==0;
28 : }
29 :
30 0 : bool notouchingface(const cube &c, int orient)
31 : {
32 0 : uint face = c.faces[DIMENSION(orient)];
33 0 : return DIM_COORD(orient) ? (face&0x80808080)==0 : ((0x88888888-face)&0x08080808) == 0;
34 : }
35 :
36 0 : bool cube::mincubeface(const cube &cu, int orient, const ivec &co, int size, facebounds &orig) const
37 : {
38 0 : ivec no;
39 : int nsize;
40 0 : const cube &nc = rootworld.neighborcube(orient, co, size, no, nsize);
41 : facebounds mincf;
42 0 : mincf.u1 = orig.u2;
43 0 : mincf.u2 = orig.u1;
44 0 : mincf.v1 = orig.v2;
45 0 : mincf.v2 = orig.v1;
46 0 : mincubeface(nc, oppositeorient(orient), no, nsize, orig, mincf, cu.material&Mat_Alpha ? Mat_Air : Mat_Alpha, Mat_Alpha);
47 0 : bool smaller = false;
48 0 : if(mincf.u1 > orig.u1)
49 : {
50 0 : orig.u1 = mincf.u1;
51 0 : smaller = true;
52 : }
53 0 : if(mincf.u2 < orig.u2)
54 : {
55 0 : orig.u2 = mincf.u2;
56 0 : smaller = true;
57 : }
58 0 : if(mincf.v1 > orig.v1)
59 : {
60 0 : orig.v1 = mincf.v1;
61 0 : smaller = true;
62 : }
63 0 : if(mincf.v2 < orig.v2)
64 : {
65 0 : orig.v2 = mincf.v2;
66 0 : smaller = true;
67 : }
68 0 : return smaller;
69 : }
70 :
71 : template <> struct std::hash<cube::plink>
72 : {
73 384 : size_t operator()(const cube::plink& x) const
74 : {
75 384 : return static_cast<uint>(x.from.x)^(static_cast<uint>(x.from.y)<<8);
76 : }
77 : };
78 :
79 0 : void cube::freecubeext(cube &c)
80 : {
81 0 : if(c.ext)
82 : {
83 0 : delete[] reinterpret_cast<uchar *>(c.ext);
84 0 : c.ext = nullptr;
85 : }
86 0 : }
87 :
88 16 : void cube::discardchildren(bool fixtex, int depth)
89 : {
90 16 : visible = 0;
91 16 : merged = 0;
92 16 : if(ext)
93 : {
94 0 : if(ext->va)
95 : {
96 0 : destroyva(ext->va);
97 : }
98 0 : ext->va = nullptr;
99 0 : ext->tjoints = -1;
100 0 : freeoctaentities(*this);
101 0 : freecubeext(*this);
102 : }
103 16 : if(children)
104 : {
105 1 : uint filled = faceempty;
106 9 : for(int i = 0; i < 8; ++i)
107 : {
108 8 : (*children)[i].discardchildren(fixtex, depth+1);
109 8 : filled |= (*children)[i].faces[0];
110 : }
111 1 : if(fixtex)
112 : {
113 0 : for(int i = 0; i < 6; ++i)
114 : {
115 0 : texture[i] = getmippedtexture(*this, i);
116 : }
117 0 : if(depth > 0 && filled != faceempty)
118 : {
119 0 : faces[0] = facesolid;
120 : }
121 : }
122 1 : delete children;
123 1 : children = nullptr;
124 1 : allocnodes--;
125 : }
126 16 : }
127 :
128 0 : bool cube::isvalidcube() const
129 : {
130 0 : clipplanes p;
131 0 : genclipbounds(*this, ivec(0, 0, 0), 256, p);
132 0 : genclipplanes(*this, ivec(0, 0, 0), 256, p);
133 : // test that cube is convex
134 0 : for(uint i = 0; i < 8; ++i)
135 : {
136 0 : vec v = p.v[i];
137 0 : for(uint j = 0; j < p.size; ++j)
138 : {
139 0 : if(p.p[j].dist(v)>1e-3f)
140 : {
141 0 : return false;
142 : }
143 : }
144 : }
145 0 : return true;
146 : }
147 :
148 0 : bool cube::poly::clippoly(const facebounds &b)
149 : {
150 0 : std::array<pvert, Face_MaxVerts+4> verts1,
151 0 : verts2;
152 0 : int numverts1 = 0,
153 0 : numverts2 = 0,
154 0 : px = verts[numverts-1].x,
155 0 : py = verts[numverts-1].y;
156 0 : for(int i = 0; i < numverts; ++i)
157 : {
158 0 : int x = verts[i].x,
159 0 : y = verts[i].y;
160 0 : if(x < b.u1)
161 : {
162 0 : if(px > b.u2)
163 : {
164 0 : verts1[numverts1++] = pvert(b.u2, y + ((y - py)*(b.u2 - x))/(x - px));
165 : }
166 0 : if(px > b.u1)
167 : {
168 0 : verts1[numverts1++] = pvert(b.u1, y + ((y - py)*(b.u1 - x))/(x - px));
169 : }
170 : }
171 0 : else if(x > b.u2)
172 : {
173 0 : if(px < b.u1)
174 : {
175 0 : verts1[numverts1++] = pvert(b.u1, y + ((y - py)*(b.u1 - x))/(x - px));
176 : }
177 0 : if(px < b.u2)
178 : {
179 0 : verts1[numverts1++] = pvert(b.u2, y + ((y - py)*(b.u2 - x))/(x - px));
180 : }
181 : }
182 : else
183 : {
184 0 : if(px < b.u1)
185 : {
186 0 : if(x > b.u1)
187 : {
188 0 : verts1[numverts1++] = pvert(b.u1, y + ((y - py)*(b.u1 - x))/(x - px));
189 : }
190 : }
191 0 : else if(px > b.u2 && x < b.u2)
192 : {
193 0 : verts1[numverts1++] = pvert(b.u2, y + ((y - py)*(b.u2 - x))/(x - px));
194 : }
195 0 : verts1[numverts1++] = pvert(x, y);
196 : }
197 0 : px = x;
198 0 : py = y;
199 : }
200 0 : if(numverts1 < 3)
201 : {
202 0 : return false;
203 : }
204 0 : px = verts1[numverts1-1].x;
205 0 : py = verts1[numverts1-1].y;
206 0 : for(int i = 0; i < numverts1; ++i)
207 : {
208 0 : int x = verts1[i].x, y = verts1[i].y;
209 0 : if(y < b.v1)
210 : {
211 0 : if(py > b.v2)
212 : {
213 0 : verts2[numverts2++] = pvert(x + ((x - px)*(b.v2 - y))/(y - py), b.v2);
214 : }
215 0 : if(py > b.v1)
216 : {
217 0 : verts2[numverts2++] = pvert(x + ((x - px)*(b.v1 - y))/(y - py), b.v1);
218 : }
219 : }
220 0 : else if(y > b.v2)
221 : {
222 0 : if(py < b.v1)
223 : {
224 0 : verts2[numverts2++] = pvert(x + ((x - px)*(b.v1 - y))/(y - py), b.v1);
225 : }
226 0 : if(py < b.v2)
227 : {
228 0 : verts2[numverts2++] = pvert(x + ((x - px)*(b.v2 - y))/(y - py), b.v2);
229 : }
230 : }
231 : else
232 : {
233 0 : if(py < b.v1)
234 : {
235 0 : if(y > b.v1)
236 : {
237 0 : verts2[numverts2++] = pvert(x + ((x - px)*(b.v1 - y))/(y - py), b.v1);
238 : }
239 : }
240 0 : else if(py > b.v2 && y < b.v2)
241 : {
242 0 : verts2[numverts2++] = pvert(x + ((x - px)*(b.v2 - y))/(y - py), b.v2);
243 : }
244 0 : verts2[numverts2++] = pvert(x, y);
245 : }
246 0 : px = x;
247 0 : py = y;
248 : }
249 0 : if(numverts2 < 3)
250 : {
251 0 : return false;
252 : }
253 0 : if(numverts2 > Face_MaxVerts)
254 : {
255 0 : return false;
256 : }
257 0 : std::memcpy(verts, verts2.data(), numverts2*sizeof(pvert));
258 0 : numverts = numverts2;
259 0 : return true;
260 : }
261 :
262 48 : bool cube::genpoly(int orient, const ivec &o, int size, int vis, ivec &n, int &offset, poly &p)
263 : {
264 48 : int dim = DIMENSION(orient),
265 48 : coord = DIM_COORD(orient);
266 48 : std::array<ivec, 4> v;
267 48 : genfaceverts(*this, orient, v);
268 48 : if(flataxisface(*this, orient))
269 : {
270 48 : n = ivec(0, 0, 0);
271 48 : n[dim] = coord ? 1 : -1;
272 : }
273 : else
274 : {
275 0 : if(faceconvexity(v))
276 : {
277 0 : return false;
278 : }
279 0 : n.cross(ivec(v[1]).sub(v[0]), ivec(v[2]).sub(v[0]));
280 0 : if(!n)
281 : {
282 0 : n.cross(ivec(v[2]).sub(v[0]), ivec(v[3]).sub(v[0]));
283 : }
284 0 : reduceslope(n);
285 : }
286 :
287 48 : ivec po = ivec(o).mask(0xFFF).shl(3);
288 240 : for(int k = 0; k < 4; ++k)
289 : {
290 192 : v[k].mul(size).add(po);
291 : }
292 48 : offset = -n.dot(v[3]);
293 48 : int r = R[dim],
294 48 : c = C[dim],
295 48 : order = vis&4 ? 1 : 0;
296 48 : p.numverts = 0;
297 48 : if(coord)
298 : {
299 24 : const ivec &v0 = v[order];
300 24 : p.verts[p.numverts++] = pvert(v0[c], v0[r]);
301 24 : if(vis&1)
302 : {
303 24 : const ivec &v1 = v[order+1];
304 24 : p.verts[p.numverts++] = pvert(v1[c], v1[r]);
305 : }
306 24 : const ivec &v2 = v[order+2];
307 24 : p.verts[p.numverts++] = pvert(v2[c], v2[r]);
308 24 : if(vis&2)
309 : {
310 24 : const ivec &v3 = v[(order+3)&3];
311 24 : p.verts[p.numverts++] = pvert(v3[c], v3[r]);
312 : }
313 : }
314 : else
315 : {
316 : //3&1 are checked, 0&2 are not
317 24 : if(vis&2)
318 : {
319 24 : const ivec &v3 = v[(order+3)&3];
320 24 : p.verts[p.numverts++] = pvert(v3[c], v3[r]);
321 : }
322 24 : const ivec &v2 = v[order+2];
323 24 : p.verts[p.numverts++] = pvert(v2[c], v2[r]);
324 24 : if(vis&1)
325 : {
326 24 : const ivec &v1 = v[order+1];
327 24 : p.verts[p.numverts++] = pvert(v1[c], v1[r]);
328 : }
329 24 : const ivec &v0 = v[order];
330 24 : p.verts[p.numverts++] = pvert(v0[c], v0[r]);
331 : }
332 :
333 48 : if(faceedges(*this, orient) != facesolid)
334 : {
335 0 : int px = static_cast<int>(p.verts[p.numverts-2].x) - static_cast<int>(p.verts[p.numverts-3].x),
336 0 : py = static_cast<int>(p.verts[p.numverts-2].y) - static_cast<int>(p.verts[p.numverts-3].y),
337 0 : cx = static_cast<int>(p.verts[p.numverts-1].x) - static_cast<int>(p.verts[p.numverts-2].x),
338 0 : cy = static_cast<int>(p.verts[p.numverts-1].y) - static_cast<int>(p.verts[p.numverts-2].y),
339 0 : dir = px*cy - py*cx;
340 0 : if(dir > 0)
341 : {
342 0 : return false;
343 : }
344 0 : if(!dir)
345 : {
346 0 : if(p.numverts < 4)
347 : {
348 0 : return false;
349 : }
350 0 : p.verts[p.numverts-2] = p.verts[p.numverts-1];
351 0 : p.numverts--;
352 : }
353 0 : px = cx;
354 0 : py = cy;
355 0 : cx = static_cast<int>(p.verts[0].x) - static_cast<int>(p.verts[p.numverts-1].x);
356 0 : cy = static_cast<int>(p.verts[0].y) - static_cast<int>(p.verts[p.numverts-1].y);
357 0 : dir = px*cy - py*cx;
358 0 : if(dir > 0)
359 : {
360 0 : return false;
361 : }
362 0 : if(!dir)
363 : {
364 0 : if(p.numverts < 4)
365 : {
366 0 : return false;
367 : }
368 0 : p.numverts--;
369 : }
370 0 : px = cx;
371 0 : py = cy;
372 0 : cx = static_cast<int>(p.verts[1].x) - static_cast<int>(p.verts[0].x);
373 0 : cy = static_cast<int>(p.verts[1].y) - static_cast<int>(p.verts[0].y);
374 0 : dir = px*cy - py*cx;
375 0 : if(dir > 0)
376 : {
377 0 : return false;
378 : }
379 0 : if(!dir)
380 : {
381 0 : if(p.numverts < 4)
382 : {
383 0 : return false;
384 : }
385 0 : p.verts[0] = p.verts[p.numverts-1];
386 0 : p.numverts--;
387 : }
388 0 : px = cx;
389 0 : py = cy;
390 0 : cx = static_cast<int>(p.verts[2].x) - static_cast<int>(p.verts[1].x);
391 0 : cy = static_cast<int>(p.verts[2].y) - static_cast<int>(p.verts[1].y);
392 0 : dir = px*cy - py*cx;
393 0 : if(dir > 0)
394 : {
395 0 : return false;
396 : }
397 0 : if(!dir)
398 : {
399 0 : if(p.numverts < 4)
400 : {
401 0 : return false;
402 : }
403 0 : p.verts[1] = p.verts[2];
404 0 : p.verts[2] = p.verts[3];
405 0 : p.numverts--;
406 : }
407 : }
408 48 : p.c = this;
409 48 : p.merged = false;
410 48 : if(minface && size >= 1<<minface && touchingface(*this, orient))
411 : {
412 : facebounds b;
413 0 : b.u1 = b.u2 = p.verts[0].x;
414 0 : b.v1 = b.v2 = p.verts[0].y;
415 0 : for(int i = 1; i < p.numverts; i++)
416 : {
417 0 : const pvert &v = p.verts[i];
418 0 : b.u1 = std::min(b.u1, v.x);
419 0 : b.u2 = std::max(b.u2, v.x);
420 0 : b.v1 = std::min(b.v1, v.y);
421 0 : b.v2 = std::max(b.v2, v.y);
422 : }
423 0 : if(mincubeface(*this, orient, o, size, b) && p.clippoly(b))
424 : {
425 0 : p.merged = true;
426 : }
427 : }
428 48 : return true;
429 : }
430 :
431 0 : bool cube::poly::mergepolys(std::unordered_set<plink> &links, std::deque<const plink *> &queue, int owner, poly &q, const pedge &e)
432 : {
433 0 : int pe = -1,
434 0 : qe = -1;
435 0 : for(int i = 0; i < numverts; ++i)
436 : {
437 0 : if(verts[i] == e.from)
438 : {
439 0 : pe = i;
440 0 : break;
441 : }
442 : }
443 0 : for(int i = 0; i < q.numverts; ++i)
444 : {
445 0 : if(q.verts[i] == e.to)
446 : {
447 0 : qe = i;
448 0 : break;
449 : }
450 : }
451 0 : if(pe < 0 || qe < 0)
452 : {
453 0 : return false;
454 : }
455 0 : if(verts[(pe+1)%numverts] != e.to || q.verts[(qe+1)%q.numverts] != e.from)
456 : {
457 0 : return false;
458 : }
459 : /*
460 : * c----d
461 : * | |
462 : * F----T
463 : * | P |
464 : * b----a
465 : */
466 0 : pvert mergeverts[2*Face_MaxVerts];
467 0 : int nummergeverts = 0,
468 0 : index = pe+2; // starts at A = T+1, ends at F = T+this.numverts
469 0 : for(int i = 0; i < numverts-1; ++i)
470 : {
471 0 : if(index >= numverts)
472 : {
473 0 : index -= numverts;
474 : }
475 0 : mergeverts[nummergeverts++] = verts[index++];
476 : }
477 0 : index = qe+2; // starts at C = T+2 = F+1, ends at T = T+q.numverts
478 0 : int px = static_cast<int>(mergeverts[nummergeverts-1].x) - static_cast<int>(mergeverts[nummergeverts-2].x),
479 0 : py = static_cast<int>(mergeverts[nummergeverts-1].y) - static_cast<int>(mergeverts[nummergeverts-2].y);
480 0 : for(int i = 0; i < q.numverts-1; ++i)
481 : {
482 0 : if(index >= q.numverts)
483 : {
484 0 : index -= q.numverts;
485 : }
486 0 : const pvert &src = q.verts[index++];
487 0 : int cx = static_cast<int>(src.x) - static_cast<int>(mergeverts[nummergeverts-1].x),
488 0 : cy = static_cast<int>(src.y) - static_cast<int>(mergeverts[nummergeverts-1].y),
489 0 : dir = px*cy - py*cx;
490 0 : if(dir > 0)
491 : {
492 0 : return false;
493 : }
494 0 : if(!dir)
495 : {
496 0 : nummergeverts--;
497 : }
498 0 : mergeverts[nummergeverts++] = src;
499 0 : px = cx;
500 0 : py = cy;
501 : }
502 0 : int cx = static_cast<int>(mergeverts[0].x) - static_cast<int>(mergeverts[nummergeverts-1].x),
503 0 : cy = static_cast<int>(mergeverts[0].y) - static_cast<int>(mergeverts[nummergeverts-1].y),
504 0 : dir = px*cy - py*cx;
505 0 : if(dir > 0)
506 : {
507 0 : return false;
508 : }
509 0 : if(!dir)
510 : {
511 0 : nummergeverts--;
512 : }
513 0 : if(nummergeverts > Face_MaxVerts)
514 : {
515 0 : return false;
516 : }
517 0 : q.merged = true;
518 0 : q.numverts = 0;
519 0 : merged = true;
520 0 : numverts = nummergeverts;
521 0 : std::memcpy(verts, mergeverts, nummergeverts*sizeof(pvert));
522 0 : int prev = numverts-1;
523 0 : for(int j = 0; j < numverts; ++j)
524 : {
525 0 : pedge e(verts[prev], verts[j]);
526 0 : int order = e.from.x > e.to.x || (e.from.x == e.to.x && e.from.y > e.to.y) ? 1 : 0;
527 0 : if(order)
528 : {
529 0 : std::swap(e.from, e.to);
530 : }
531 :
532 0 : plink l;
533 0 : auto itr = links.find(e); //search for a plink that looks like the pedge we have
534 0 : if(itr != links.end())
535 : {
536 0 : l = *itr;
537 0 : links.erase(e); // we will place an updated verson of this immutable object at the end
538 : }
539 : else
540 : {
541 0 : l = e; //even though we searched find(e), l and e are NOT the same because they are of different types (l is derived)
542 : }
543 0 : bool shouldqueue = l.polys[order] < 0 && l.polys[order^1] >= 0;
544 0 : l.polys[order] = owner;
545 0 : links.insert(l);
546 0 : if(shouldqueue)
547 : {
548 0 : queue.push_back(&*links.find(l));
549 : }
550 0 : prev = j;
551 : }
552 :
553 0 : return true;
554 : }
555 :
556 0 : void cube::addmerge(int orient, const ivec &n, int offset, poly &p)
557 : {
558 0 : merged |= 1<<orient;
559 0 : if(!p.numverts)
560 : {
561 0 : if(ext)
562 : {
563 0 : ext->surfaces[orient] = surfaceinfo();
564 : }
565 0 : return;
566 : }
567 : std::array<vertinfo, Face_MaxVerts> verts;
568 0 : surfaceinfo surf = surfaceinfo();
569 0 : surf.numverts |= p.numverts;
570 0 : int dim = DIMENSION(orient),
571 0 : coord = DIM_COORD(orient),
572 0 : c = C[dim],
573 0 : r = R[dim];
574 0 : for(int k = 0; k < p.numverts; ++k)
575 : {
576 0 : const pvert &src = p.verts[coord ? k : p.numverts-1-k];
577 0 : vertinfo &dst = verts[k];
578 0 : ivec v;
579 0 : v[c] = src.x;
580 0 : v[r] = src.y;
581 0 : v[dim] = -(offset + n[c]*src.x + n[r]*src.y)/n[dim];
582 0 : dst.set(v);
583 : }
584 0 : if(ext)
585 : {
586 0 : const surfaceinfo &oldsurf = ext->surfaces[orient];
587 0 : int numverts = oldsurf.numverts&Face_MaxVerts;
588 0 : if(numverts == p.numverts)
589 : {
590 0 : ivec v0 = verts[0].getxyz();
591 0 : const vertinfo *oldverts = ext->verts() + oldsurf.verts;
592 0 : for(int j = 0; j < numverts; ++j)
593 : {
594 0 : if(v0 == oldverts[j].getxyz())
595 : {
596 0 : for(int k = 1; k < numverts; ++k)
597 : {
598 0 : if(++j >= numverts)
599 : {
600 0 : j = 0;
601 : }
602 0 : if(verts[k].getxyz() != oldverts[j].getxyz())
603 : {
604 0 : goto nomatch;
605 : }
606 : }
607 0 : return;
608 : }
609 : }
610 0 : nomatch:;
611 : }
612 : }
613 0 : setsurface(*this, orient, surf, verts.data(), p.numverts);
614 : }
615 :
616 90 : void cube::clearmerge(int orient)
617 : {
618 90 : if(merged&(1<<orient))
619 : {
620 0 : merged &= ~(1<<orient);
621 0 : if(ext)
622 : {
623 0 : ext->surfaces[orient] = surfaceinfo();
624 : }
625 : }
626 90 : }
627 :
628 12 : void cube::addmerges(int orient, const ivec &n, int offset, std::deque<poly> &polys)
629 : {
630 60 : for(poly &p : polys)
631 : {
632 48 : if(p.merged)
633 : {
634 0 : (*(p.c)).addmerge(orient, n, offset, p);
635 : }
636 : else
637 : {
638 48 : (*(p.c)).clearmerge(orient);
639 : }
640 : }
641 12 : }
642 :
643 12 : void cube::mergepolys(int orient, const ivec &n, int offset, std::deque<poly> &polys)
644 : {
645 12 : if(polys.size() <= 1)
646 : {
647 0 : addmerges(orient, n, offset, polys);
648 0 : return;
649 : }
650 12 : std::unordered_set<plink> links(polys.size() <= 32 ? 128 : 1024);
651 12 : std::deque<const plink *> queue;
652 60 : for(uint i = 0; i < polys.size(); i++)
653 : {
654 48 : const poly &p = polys[i];
655 48 : int prev = p.numverts-1;
656 240 : for(int j = 0; j < p.numverts; ++j)
657 : {
658 192 : pedge e(p.verts[prev], p.verts[j]);
659 192 : int order = e.from.x > e.to.x || (e.from.x == e.to.x && e.from.y > e.to.y) ? 1 : 0;
660 192 : if(order)
661 : {
662 96 : std::swap(e.from, e.to);
663 : }
664 192 : plink l;
665 192 : auto itr = links.find(e);
666 192 : if(itr != links.end())
667 : {
668 0 : l = *itr;
669 0 : links.erase(e);
670 : }
671 192 : l.polys[order] = i;
672 192 : links.insert(l);
673 192 : if(l.polys[0] >= 0 && l.polys[1] >= 0)
674 : {
675 0 : queue.push_back(&*links.find(l));
676 : }
677 192 : prev = j;
678 : }
679 : }
680 12 : std::deque<const plink *> nextqueue;
681 12 : while(queue.size())
682 : {
683 0 : for(const plink *&l : queue)
684 : {
685 0 : if(l->polys[0] >= 0 && l->polys[1] >= 0)
686 : {
687 0 : polys[l->polys[0]].mergepolys(links, nextqueue, l->polys[0], polys[l->polys[1]], *l);
688 : }
689 : }
690 0 : queue.clear();
691 0 : queue.insert(queue.end(), nextqueue.begin(), nextqueue.end());
692 0 : nextqueue.clear();
693 : }
694 12 : addmerges(orient, n, offset, polys);
695 12 : }
696 :
697 36 : bool operator==(const cube::cfkey &x, const cube::cfkey &y)
698 : {
699 36 : return x.orient == y.orient && x.tex == y.tex && x.n == y.n && x.offset == y.offset && x.material==y.material;
700 : }
701 :
702 : template<>
703 : struct std::hash<cube::cfkey>
704 : {
705 48 : size_t operator()(const cube::cfkey &k) const
706 : {
707 : auto ivechash = std::hash<ivec>();
708 48 : return ivechash(k.n)^k.offset^k.tex^k.orient^k.material;
709 : }
710 : };
711 :
712 : //recursively goes through children of cube passed and attempts to merge faces together
713 4 : void cube::genmerges(cube * root, const ivec &o, int size)
714 : {
715 4 : static std::unordered_map<cfkey, cfpolys> cpolys;
716 4 : neighborstack[++neighbordepth] = this;
717 36 : for(int i = 0; i < 8; ++i)
718 : {
719 32 : ivec co(i, o, size);
720 : int vis;
721 32 : if(this[i].children)
722 : {
723 2 : (this[i]).children->at(0).genmerges(root, co, size>>1);
724 : }
725 30 : else if(!(this[i].isempty()))
726 : {
727 105 : for(int j = 0; j < 6; ++j)
728 : {
729 90 : if((vis = visibletris(this[i], j, co, size)))
730 : {
731 90 : cfkey k;
732 90 : poly p;
733 90 : if(size < 1<<maxmerge && this != root)
734 : {
735 48 : if(genpoly(j, co, size, vis, k.n, k.offset, p))
736 : {
737 48 : k.orient = j;
738 48 : k.tex = this[i].texture[j];
739 48 : k.material = this[i].material&Mat_Alpha;
740 48 : cpolys[k].polys.push_back(p);
741 48 : continue;
742 : }
743 : }
744 42 : else if(minface && size >= 1<<minface && touchingface(this[i], j))
745 : {
746 0 : if(genpoly(j, co, size, vis, k.n, k.offset, p) && p.merged)
747 : {
748 0 : this[i].addmerge( j, k.n, k.offset, p);
749 0 : continue;
750 : }
751 : }
752 42 : this[i].clearmerge(j);
753 : }
754 : }
755 : }
756 32 : if((size == 1<<maxmerge || this == root) && cpolys.size())
757 : {
758 13 : for(auto &[k, t] : cpolys)
759 : {
760 12 : mergepolys(k.orient, k.n, k.offset, t.polys);
761 : }
762 1 : cpolys.clear();
763 : }
764 : }
765 4 : --neighbordepth;
766 4 : }
767 :
768 2 : void cube::calcmerges()
769 : {
770 2 : genmerges(this);
771 2 : }
|