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