LCOV - code coverage report
Current view: top level - engine/world - octacube.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 123 425 28.9 %
Date: 2024-11-22 05:07:59 Functions: 10 18 55.6 %

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

Generated by: LCOV version 1.14