LCOV - code coverage report
Current view: top level - engine/world - octacube.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 28.9 % 426 123
Test Date: 2025-05-25 06:55:32 Functions: 55.6 % 18 10

            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 : }
        

Generated by: LCOV version 2.0-1