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