LCOV - code coverage report
Current view: top level - engine/model - vertmodel.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 0.0 % 238 0
Test Date: 2026-05-09 04:28:55 Functions: 0.0 % 31 0

            Line data    Source code
       1              : /**
       2              :  * @file vertmodel.cpp
       3              :  * @brief Vertex model support
       4              :  *
       5              :  * Support for vertex animated or static vertex models (as opposed to skeletal models
       6              :  * in skelmodel)
       7              :  */
       8              : #include "../libprimis-headers/cube.h"
       9              : #include "../../shared/geomexts.h"
      10              : #include "../../shared/glemu.h"
      11              : #include "../../shared/glexts.h"
      12              : 
      13              : #include <format>
      14              : #include <memory>
      15              : #include <optional>
      16              : 
      17              : #include "interface/console.h"
      18              : #include "interface/control.h"
      19              : 
      20              : #include "render/rendergl.h"
      21              : #include "render/renderlights.h"
      22              : #include "render/rendermodel.h"
      23              : #include "render/shader.h"
      24              : #include "render/shaderparam.h"
      25              : #include "render/texture.h"
      26              : 
      27              : #include "world/entities.h"
      28              : #include "world/octaworld.h"
      29              : #include "world/bih.h"
      30              : 
      31              : #include "model.h"
      32              : #include "ragdoll.h"
      33              : #include "animmodel.h"
      34              : #include "vertmodel.h"
      35              : 
      36              : //==============================================================================
      37              : // vertmodel object
      38              : //==============================================================================
      39              : 
      40            0 : vertmodel::meshgroup * vertmodel::loadmeshes(const char *name, float smooth)
      41              : {
      42            0 :     vertmeshgroup *group = newmeshes();
      43            0 :     if(!group->load(name, smooth))
      44              :     {
      45            0 :         delete group;
      46            0 :         return nullptr;
      47              :     }
      48            0 :     return group;
      49              : }
      50              : 
      51            0 : vertmodel::meshgroup * vertmodel::sharemeshes(const char *name, float smooth)
      52              : {
      53            0 :     if(meshgroups.find(name) == meshgroups.end())
      54              :     {
      55            0 :         meshgroup *group = loadmeshes(name, smooth);
      56            0 :         if(!group)
      57              :         {
      58            0 :             return nullptr;
      59              :         }
      60            0 :         meshgroups[group->groupname()] = group;
      61              :     }
      62            0 :     return meshgroups[name];
      63              : }
      64              : 
      65            0 : vertmodel::vertmodel(std::string name) : animmodel(std::move(name))
      66              : {
      67            0 : }
      68              : 
      69              : //==============================================================================
      70              : // vertmodel::vbocacheentry object
      71              : //==============================================================================
      72              : 
      73            0 : vertmodel::vbocacheentry::vbocacheentry() : vbuf(0)
      74              : {
      75            0 :     as.cur.fr1 = as.prev.fr1 = -1;
      76            0 : }
      77              : 
      78              : //==============================================================================
      79              : // vertmodel::vertmesh object
      80              : //==============================================================================
      81              : 
      82            0 : vertmodel::vertmesh::vertmesh() : verts(0), tcverts(0), tris(0)
      83              : {
      84            0 : }
      85              : 
      86            0 : vertmodel::vertmesh::vertmesh(std::string_view name, meshgroup *m) :
      87              :     Mesh(name, m),
      88            0 :     verts(0),
      89            0 :     tcverts(0),
      90            0 :     tris(0)
      91              : {
      92            0 : }
      93              : 
      94            0 : vertmodel::vertmesh::~vertmesh()
      95              : {
      96            0 :     delete[] verts;
      97            0 :     delete[] tcverts;
      98            0 :     delete[] tris;
      99            0 : }
     100              : 
     101            0 : void vertmodel::vertmesh::smoothnorms(float limit, bool areaweight)
     102              : {
     103            0 :     if((static_cast<vertmeshgroup *>(group))->numframes == 1)
     104              :     {
     105            0 :         Mesh::smoothnorms<vertmodel>(verts, numverts, tris, numtris, limit, areaweight);
     106              :     }
     107              :     else
     108              :     {
     109            0 :         buildnorms(areaweight);
     110              :     }
     111            0 : }
     112              : 
     113            0 : void vertmodel::vertmesh::buildnorms(bool areaweight)
     114              : {
     115            0 :     Mesh::buildnorms<vertmodel>(verts, numverts, tris, numtris, areaweight, (static_cast<vertmeshgroup *>(group))->numframes);
     116            0 : }
     117              : 
     118            0 : void vertmodel::vertmesh::calctangents(bool areaweight)
     119              : {
     120            0 :     Mesh::calctangents<vertmodel, vertmodel::tcvert>(verts, tcverts, numverts, tris, numtris, areaweight, (static_cast<vertmeshgroup *>(group))->numframes);
     121            0 : }
     122              : 
     123            0 : void vertmodel::vertmesh::calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) const
     124              : {
     125            0 :     for(int j = 0; j < numverts; ++j)
     126              :     {
     127            0 :         vec v = m.transform(verts[j].pos);
     128            0 :         bbmin.min(v);
     129            0 :         bbmax.max(v);
     130              :     }
     131            0 : }
     132              : 
     133            0 : void vertmodel::vertmesh::genBIH(BIH::mesh &m) const
     134              : {
     135            0 :     m.setmesh(reinterpret_cast<const BIH::mesh::tri *>(tris), numtris,
     136            0 :               reinterpret_cast<const uchar *>(&verts->pos), sizeof(vert),
     137            0 :               reinterpret_cast<const uchar *>(&tcverts->tc), sizeof(tcvert));
     138            0 : }
     139              : 
     140            0 : void vertmodel::vertmesh::genshadowmesh(std::vector<triangle> &out, const matrix4x3 &m) const
     141              : {
     142            0 :     for(int j = 0; j < numtris; ++j)
     143              :     {
     144            0 :         out.emplace_back(m.transform(verts[tris[j].vert[0]].pos),
     145            0 :                          m.transform(verts[tris[j].vert[1]].pos),
     146            0 :                          m.transform(verts[tris[j].vert[2]].pos));
     147              :     }
     148            0 : }
     149              : 
     150            0 : void vertmodel::vertmesh::assignvert(vvertg &vv, const tcvert &tc, const vert &v)
     151              : {
     152            0 :     vv.pos = vec4<half>(v.pos, 1);
     153            0 :     vv.tc = tc.tc;
     154            0 :     vv.tangent = v.tangent;
     155            0 : }
     156              : 
     157            0 : int vertmodel::vertmesh::genvbo(std::vector<uint> &idxs, int offset)
     158              : {
     159            0 :     voffset = offset;
     160            0 :     for(int i = 0; i < numtris; ++i)
     161              :     {
     162            0 :         const tri &t = tris[i];
     163            0 :         for(int j = 0; j < 3; ++j)
     164              :         {
     165            0 :             idxs.push_back(voffset+t.vert[j]);
     166              :         }
     167              :     }
     168            0 :     minvert = voffset;
     169            0 :     maxvert = voffset + numverts-1;
     170            0 :     elen = idxs.size();
     171            0 :     return numverts;
     172              : }
     173              : 
     174            0 : void vertmodel::vertmesh::render() const
     175              : {
     176            0 :     if(!Shader::lastshader)
     177              :     {
     178            0 :         return;
     179              :     }
     180            0 :     glDrawRangeElements(GL_TRIANGLES, minvert, maxvert, elen, GL_UNSIGNED_INT, nullptr);
     181            0 :     glde++;
     182            0 :     xtravertsva += numverts;
     183              : }
     184              : 
     185              : //==============================================================================
     186              : // vertmodel::vertmeshgroup object
     187              : //==============================================================================
     188              : 
     189            0 : vertmodel::vertmeshgroup::vertmeshgroup()
     190            0 :     : numframes(0), tags(nullptr), numtags(0), ebuf(0), vlen(0), vertsize(0), vdata(nullptr)
     191              : {
     192            0 : }
     193              : 
     194            0 : vertmodel::vertmeshgroup::~vertmeshgroup()
     195              : {
     196            0 :     delete[] tags;
     197            0 :     if(ebuf)
     198              :     {
     199            0 :         glDeleteBuffers(1, &ebuf);
     200              :     }
     201            0 :     for(size_t i = 0; i < maxvbocache; ++i)
     202              :     {
     203            0 :         if(vbocache[i].vbuf)
     204              :         {
     205            0 :             glDeleteBuffers(1, &vbocache[i].vbuf);
     206              :         }
     207              :     }
     208            0 :     delete[] vdata;
     209            0 : }
     210              : 
     211            0 : void vertmodel::vertmeshgroup::concattagtransform(int, const matrix4x3 &, matrix4x3 &) const
     212              : {
     213            0 : }
     214              : 
     215            0 : std::optional<size_t> vertmodel::vertmeshgroup::findtag(std::string_view name)
     216              : {
     217            0 :     for(size_t i = 0; i < numtags; ++i)
     218              :     {
     219            0 :         if(tags[i].name == name)
     220              :         {
     221            0 :             return i;
     222              :         }
     223              :     }
     224            0 :     return std::nullopt;
     225              : }
     226              : 
     227            0 : bool vertmodel::vertmeshgroup::addtag(std::string_view name, const matrix4x3 &matrix)
     228              : {
     229            0 :     std::optional<size_t> idx = findtag(name);
     230            0 :     if(idx)
     231              :     {
     232            0 :         if(!testtags)
     233              :         {
     234            0 :             return false;
     235              :         }
     236            0 :         for(int i = 0; i < numframes; ++i)
     237              :         {
     238            0 :             tag &t = tags[i*numtags + *idx];
     239            0 :             t.matrix = matrix;
     240              :         }
     241              :     }
     242              :     else
     243              :     {
     244            0 :         tag *newtags = new tag[(numtags+1)*numframes];
     245            0 :         for(int i = 0; i < numframes; ++i)
     246              :         {
     247            0 :             tag *dst = &newtags[(numtags+1)*i],
     248            0 :                 *src = &tags[numtags*i];
     249            0 :             if(!i)
     250              :             {
     251            0 :                 for(size_t j = 0; j < numtags; ++j)
     252              :                 {
     253            0 :                     std::swap(dst[j].name, src[j].name);
     254              :                 }
     255            0 :                 dst[numtags].name = name;
     256              :             }
     257            0 :             for(size_t j = 0; j < numtags; ++j)
     258              :             {
     259            0 :                 dst[j].matrix = src[j].matrix;
     260              :             }
     261            0 :             dst[numtags].matrix = matrix;
     262              :         }
     263            0 :         if(tags)
     264              :         {
     265            0 :             delete[] tags;
     266              :         }
     267            0 :         tags = newtags;
     268            0 :         numtags++;
     269              :     }
     270            0 :     return true;
     271              : }
     272              : 
     273            0 : int vertmodel::vertmeshgroup::totalframes() const
     274              : {
     275            0 :     return numframes;
     276              : }
     277              : 
     278            0 : void vertmodel::vertmeshgroup::calctagmatrix(const part *p, int i, const AnimState &as, matrix4 &matrix) const
     279              : {
     280            0 :     const matrix4x3 &tag1 = tags[as.cur.fr1*numtags + i].matrix,
     281            0 :                     &tag2 = tags[as.cur.fr2*numtags + i].matrix;
     282            0 :     matrix4x3 tag;
     283            0 :     tag.lerp(tag1, tag2, as.cur.t);
     284            0 :     if(as.interp<1)
     285              :     {
     286            0 :         const matrix4x3 &tag1p = tags[as.prev.fr1*numtags + i].matrix,
     287            0 :                         &tag2p = tags[as.prev.fr2*numtags + i].matrix;
     288            0 :         matrix4x3 tagp;
     289            0 :         tagp.lerp(tag1p, tag2p, as.prev.t);
     290            0 :         tag.lerp(tagp, tag, as.interp);
     291              :     }
     292            0 :     tag.d.mul(p->model->locationsize().w * sizescale);
     293            0 :     matrix = matrix4(tag);
     294            0 : }
     295              : 
     296            0 : void vertmodel::vertmeshgroup::genvbo(vbocacheentry &vc)
     297              : {
     298            0 :     if(!vc.vbuf)
     299              :     {
     300            0 :         glGenBuffers(1, &vc.vbuf);
     301              :     }
     302            0 :     if(ebuf)
     303              :     {
     304            0 :         return;
     305              :     }
     306              : 
     307            0 :     std::vector<uint> idxs;
     308            0 :     std::vector<std::vector<animmodel::Mesh *>::iterator> rendermeshes = getrendermeshes();
     309            0 :     vlen = 0;
     310            0 :     if(numframes>1)
     311              :     {
     312            0 :         vertsize = sizeof(vvert);
     313              : 
     314            0 :         for(std::vector<animmodel::Mesh *>::const_iterator i : rendermeshes)
     315              :         {
     316            0 :             vlen += static_cast<vertmesh *>(*i)->genvbo(idxs, vlen);
     317              :         }
     318            0 :         delete[] vdata;
     319            0 :         vdata = new uchar[vlen*vertsize];
     320            0 :         for(std::vector<animmodel::Mesh *>::const_iterator i : rendermeshes)
     321              :         {
     322            0 :             static_cast<vertmesh *>(*i)->fillverts(reinterpret_cast<vvert *>(vdata));
     323              :         }
     324              :     }
     325              :     else
     326              :     {
     327            0 :         vertsize = sizeof(vvertg);
     328            0 :         gle::bindvbo(vc.vbuf);
     329            0 :         size_t numverts = 0,
     330            0 :                htlen = 128;
     331            0 :         for(std::vector<animmodel::Mesh *>::const_iterator i : rendermeshes)
     332              :         {
     333            0 :             numverts += static_cast<vertmesh *>(*i)->numverts;
     334              :         }
     335            0 :         while(htlen < numverts)
     336              :         {
     337            0 :             htlen *= 2;
     338              :         }
     339            0 :         if(numverts*4 > htlen*3)
     340              :         {
     341            0 :             htlen *= 2;
     342              :         }
     343            0 :         int *htdata = new int[htlen];
     344            0 :         std::memset(htdata, -1, htlen*sizeof(int));
     345            0 :         std::vector<vvertg> vverts;
     346            0 :         for(std::vector<animmodel::Mesh *>::const_iterator i : rendermeshes)
     347              :         {
     348            0 :             vlen += static_cast<vertmesh *>(*i)->genvbo(idxs, vlen, vverts, htdata, htlen);
     349              :         }
     350            0 :         glBufferData(GL_ARRAY_BUFFER, vverts.size()*sizeof(vvertg), vverts.data(), GL_STATIC_DRAW);
     351            0 :         delete[] htdata;
     352            0 :         htdata = nullptr;
     353            0 :         gle::clearvbo();
     354            0 :     }
     355              : 
     356            0 :     glGenBuffers(1, &ebuf);
     357            0 :     gle::bindebo(ebuf);
     358            0 :     glBufferData(GL_ELEMENT_ARRAY_BUFFER, idxs.size()*sizeof(uint), idxs.data(), GL_STATIC_DRAW);
     359            0 :     gle::clearebo();
     360            0 : }
     361              : 
     362            0 : void vertmodel::vertmeshgroup::bindvbo(const AnimState *as, const part *p, const vbocacheentry &vc)
     363              : {
     364            0 :     if(numframes>1)
     365              :     {
     366            0 :         bindvbo<vvert>(as, p, vc);
     367              :     }
     368              :     else
     369              :     {
     370            0 :         bindvbo<vvertg>(as, p, vc);
     371              :     }
     372            0 : }
     373              : 
     374            0 : void *vertmodel::vertmeshgroup::animkey()
     375              : {
     376            0 :     return this;
     377              : }
     378              : 
     379            0 : void vertmodel::vertmeshgroup::cleanup()
     380              : {
     381            0 :     for(size_t i = 0; i < maxvbocache; ++i)
     382              :     {
     383            0 :         vbocacheentry &c = vbocache[i];
     384            0 :         if(c.vbuf)
     385              :         {
     386            0 :             glDeleteBuffers(1, &c.vbuf);
     387            0 :             c.vbuf = 0;
     388              :         }
     389            0 :         c.as.cur.fr1 = -1;
     390              :     }
     391            0 :     if(ebuf)
     392              :     {
     393            0 :         glDeleteBuffers(1, &ebuf);
     394            0 :         ebuf = 0;
     395              :     }
     396            0 : }
     397              : 
     398            0 : void vertmodel::vertmeshgroup::preload()
     399              : {
     400            0 :     if(numframes > 1)
     401              :     {
     402            0 :         return;
     403              :     }
     404            0 :     if(!vbocache[0].vbuf)
     405              :     {
     406            0 :         genvbo(vbocache[0]);
     407              :     }
     408              : }
     409              : 
     410            0 : void vertmodel::vertmeshgroup::render(const AnimState *as, float, const vec &, const vec &, dynent *, part *p)
     411              : {
     412            0 :     if(as->cur.anim & Anim_NoRender)
     413              :     {
     414            0 :         for(part::linkedpart &l : p->links)
     415              :         {
     416            0 :             calctagmatrix(p, l.tag, *as, l.matrix);
     417              :         }
     418            0 :         return;
     419              :     }
     420            0 :     vbocacheentry *vc = nullptr;
     421            0 :     if(numframes<=1)
     422              :     {
     423            0 :         vc = vbocache.data();
     424              :     }
     425              :     else
     426              :     {
     427            0 :         for(size_t i = 0; i < maxvbocache; ++i)
     428              :         {
     429            0 :             vbocacheentry &c = vbocache[i];
     430            0 :             if(!c.vbuf)
     431              :             {
     432            0 :                 continue;
     433              :             }
     434            0 :             if(c.as==*as)
     435              :             {
     436            0 :                 vc = &c;
     437            0 :                 break;
     438              :             }
     439              :         }
     440            0 :         if(!vc)
     441              :         {
     442            0 :             for(size_t i = 0; i < maxvbocache; ++i)
     443              :             {
     444            0 :                 vc = &vbocache[i];
     445            0 :                 if(!vc->vbuf || vc->millis < lastmillis)
     446              :                 {
     447              :                     break;
     448              :                 }
     449              :             }
     450              :         }
     451              :     }
     452            0 :     if(!vc->vbuf)
     453              :     {
     454            0 :         genvbo(*vc);
     455              :     }
     456            0 :     if(numframes>1)
     457              :     {
     458            0 :         if(vc->as!=*as)
     459              :         {
     460            0 :             vc->as = *as;
     461            0 :             vc->millis = lastmillis;
     462            0 :             std::vector<std::vector<animmodel::Mesh *>::iterator> rendermeshes = getrendermeshes();
     463            0 :             for(std::vector<animmodel::Mesh *>::iterator i : rendermeshes)
     464              :             {
     465            0 :                 static_cast<vertmesh *>(*i)->interpverts(*as, reinterpret_cast<vvert *>(vdata));
     466              :             }
     467            0 :             gle::bindvbo(vc->vbuf);
     468            0 :             glBufferData(GL_ARRAY_BUFFER, vlen*vertsize, vdata, GL_STREAM_DRAW);
     469            0 :         }
     470            0 :         vc->millis = lastmillis;
     471              :     }
     472            0 :     bindvbo(as, p, *vc);
     473            0 :     LOOP_RENDER_MESHES(vertmesh, m,
     474              :     {
     475              :         p->skins[i].bind(m, as); //not a skeletal model, do not need to include trailing params
     476              :         m.render();
     477              :     });
     478            0 :     for(part::linkedpart &l : p->links)
     479              :     {
     480            0 :         calctagmatrix(p, l.tag, *as, l.matrix);
     481              :     }
     482              : }
        

Generated by: LCOV version 2.0-1