LCOV - code coverage report
Current view: top level - engine/world - octacube.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 32.4 % 426 138
Test Date: 2026-05-09 04:28:55 Functions: 72.2 % 18 13

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

Generated by: LCOV version 2.0-1