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