LCOV - code coverage report
Current view: top level - engine/model - vertmodel.h (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 12.0 % 133 16
Test Date: 2025-04-16 12:09:02 Functions: 23.1 % 13 3

            Line data    Source code
       1              : #ifndef VERTMODEL_H_
       2              : #define VERTMODEL_H_
       3              : 
       4              : class vertmodel : public animmodel
       5              : {
       6              :     public:
       7              :         struct vert final
       8              :         {
       9              :             vec pos, norm;
      10              :             vec4<float> tangent;
      11              :         };
      12              : 
      13              :         struct vvert final
      14              :         {
      15              :             vec pos;
      16              :             GenericVec2<half> tc;
      17              :             squat tangent;
      18              :         };
      19              : 
      20              :         struct vvertg final
      21              :         {
      22              :             vec4<half> pos;
      23              :             GenericVec2<half> tc;
      24              :             squat tangent;
      25              :         };
      26              : 
      27              :         struct tcvert final
      28              :         {
      29              :             vec2 tc;
      30              :         };
      31              : 
      32              :         struct tri final
      33              :         {
      34              :             uint vert[3];
      35              :         };
      36              : 
      37              :         struct vbocacheentry final
      38              :         {
      39              :             GLuint vbuf;
      40              :             AnimState as;
      41              :             int millis;
      42              : 
      43              :             vbocacheentry();
      44              :         };
      45              : 
      46              :         struct vertmesh : Mesh
      47              :         {
      48              :             public:
      49              :                 vert *verts;
      50              :                 tcvert *tcverts;
      51              :                 tri *tris;
      52              :                 int numverts, numtris;
      53              : 
      54              :                 vertmesh();
      55              :                 vertmesh(std::string_view name, meshgroup *m);
      56              : 
      57              :                 virtual ~vertmesh();
      58              : 
      59              :                 void smoothnorms(float limit = 0, bool areaweight = true);
      60              :                 void buildnorms(bool areaweight = true);
      61              :                 void calctangents(bool areaweight = true);
      62              :                 void calcbb(vec &bbmin, vec &bbmax, const matrix4x3 &m) const override final;
      63              :                 void genBIH(BIH::mesh &m) const override final;
      64              :                 void genshadowmesh(std::vector<triangle> &out, const matrix4x3 &m) const override final;
      65              : 
      66              :                 static void assignvert(vvertg &vv, const tcvert &tc, const vert &v);
      67              : 
      68              :                 template<class T>
      69            0 :                 int genvbo(std::vector<uint> &idxs, int offset, std::vector<T> &vverts, int *htdata, int htlen)
      70              :                 {
      71            0 :                     voffset = offset;
      72            0 :                     minvert = UINT_MAX;
      73            0 :                     for(int i = 0; i < numtris; ++i)
      74              :                     {
      75            0 :                         const tri &t = tris[i];
      76            0 :                         for(int j = 0; j < 3; ++j)
      77              :                         {
      78            0 :                             const int index = t.vert[j];
      79            0 :                             const vert &v = verts[index];
      80            0 :                             const tcvert &tc = tcverts[index];
      81            0 :                             T vv;
      82            0 :                             assignvert(vv, tc, v);
      83              :                             const auto hashfn = std::hash<vec>();
      84            0 :                             const int htidx = hashfn(v.pos)&(htlen-1);
      85            0 :                             for(int k = 0; k < htlen; ++k)
      86              :                             {
      87            0 :                                 int &vidx = htdata[(htidx+k)&(htlen-1)];
      88            0 :                                 if(vidx < 0)
      89              :                                 {
      90            0 :                                     idxs.push_back(vverts.size());
      91            0 :                                     vidx = idxs.back();
      92            0 :                                     vverts.push_back(vv);
      93            0 :                                     break;
      94              :                                 }
      95            0 :                                 else if(!std::memcmp(&vverts[vidx], &vv, sizeof(vv)))
      96              :                                 {
      97            0 :                                     idxs.push_back(static_cast<uint>(vidx));
      98            0 :                                     minvert = std::min(minvert, idxs.back());
      99            0 :                                     break;
     100              :                                 }
     101              :                             }
     102              :                         }
     103              :                     }
     104            0 :                     minvert = std::min(minvert, static_cast<uint>(voffset));
     105            0 :                     maxvert = std::max(minvert, static_cast<uint>(vverts.size()-1));
     106            0 :                     elen = idxs.size();
     107            0 :                     return vverts.size()-voffset;
     108              :                 }
     109              : 
     110              :                 int genvbo(std::vector<uint> &idxs, int offset);
     111              : 
     112              :                 template<class T>
     113            0 :                 static void fillvert(T &vv, tcvert &tc)
     114              :                 {
     115            0 :                     vv.tc = tc.tc;
     116            0 :                 }
     117              : 
     118              :                 template<class T>
     119            0 :                 void fillverts(T *vdata)
     120              :                 {
     121            0 :                     vdata += voffset;
     122            0 :                     for(int i = 0; i < numverts; ++i)
     123              :                     {
     124            0 :                         fillvert(vdata[i], tcverts[i]);
     125              :                     }
     126            0 :                 }
     127              : 
     128              :                 template<class T>
     129            0 :                 void interpverts(const AnimState &as, T * RESTRICT vdata)
     130              :                 {
     131            0 :                     vdata += voffset;
     132            0 :                     const vert * RESTRICT vert1 = &verts[as.cur.fr1 * numverts],
     133            0 :                                * RESTRICT vert2 = &verts[as.cur.fr2 * numverts],
     134            0 :                                * RESTRICT pvert1 = as.interp<1 ? &verts[as.prev.fr1 * numverts] : nullptr,
     135            0 :                                * RESTRICT pvert2 = as.interp<1 ? &verts[as.prev.fr2 * numverts] : nullptr;
     136            0 :                     if(as.interp<1)
     137              :                     {
     138            0 :                         for(int i = 0; i < numverts; ++i)
     139              :                         {
     140            0 :                             T &v = vdata[i];
     141            0 :                             v.pos.lerp(vec().lerp(pvert1[i].pos, pvert2[i].pos, as.prev.t),
     142            0 :                                        vec().lerp(vert1[i].pos, vert2[i].pos, as.cur.t),
     143            0 :                                        as.interp);
     144            0 :                             v.tangent.lerp(vec4<float>().lerp(pvert1[i].tangent, pvert2[i].tangent, as.prev.t),
     145            0 :                                            vec4<float>().lerp(vert1[i].tangent, vert2[i].tangent, as.cur.t),
     146            0 :                                            as.interp);
     147              :                         }
     148              :                     }
     149              :                     else
     150              :                     {
     151            0 :                         for(int i = 0; i < numverts; ++i)
     152              :                         {
     153            0 :                             T &v = vdata[i];
     154            0 :                             v.pos.lerp(vert1[i].pos, vert2[i].pos, as.cur.t);
     155            0 :                             v.tangent.lerp(vert1[i].tangent, vert2[i].tangent, as.cur.t);
     156              :                         }
     157              :                     }
     158            0 :                 }
     159              : 
     160              :                 /**
     161              :                  * @brief Draws the elements in this vertmesh.
     162              :                  *
     163              :                  * Fails to draw if there is no shader assigned to Shader::lastshader.
     164              :                  *
     165              :                  * Increments glde by one and the xtravertsva counter by the number of vertices drawn.
     166              :                  */
     167              :                 void render() const;
     168              :             private:
     169              :                 int voffset, elen;
     170              :                 uint minvert, maxvert;
     171              :         };
     172              : 
     173              :         struct tag final
     174              :         {
     175              :             std::string name;
     176              :             matrix4x3 matrix;
     177              : 
     178            0 :             tag() {}
     179              :         };
     180              : 
     181              :         struct vertmeshgroup : meshgroup
     182              :         {
     183              :             int numframes;
     184              :             //size equal to numtags * numframes
     185              :             //tags are ordered beneath frames; tag1frame1, tag2frame1, tag3frame1, tag1frame2, etc
     186              :             //deleted and re-created whenever a new tag is added with addtag();
     187              :             tag *tags;
     188              :             size_t numtags;
     189              : 
     190              :             static constexpr size_t maxvbocache = 16;
     191              :             std::array<vbocacheentry, 16> vbocache;
     192              : 
     193              :             GLuint ebuf;
     194              :             int vlen, vertsize;
     195              :             uchar *vdata;
     196              : 
     197              :             vertmeshgroup();
     198              :             virtual ~vertmeshgroup();
     199              : 
     200              :             virtual void concattagtransform(int i, const matrix4x3 &m, matrix4x3 &n) const override final;
     201              :             bool addtag(std::string_view name, const matrix4x3 &matrix);
     202              :             std::optional<size_t> findtag(std::string_view name) override final;
     203              : 
     204              :             /**
     205              :              * @brief Returns the number of frames associated with this model.
     206              :              *
     207              :              * This is the numframes field in the meshgroup object.
     208              :              */
     209              :             int totalframes() const override final;
     210              :             void calctagmatrix(const part *p, int i, const AnimState &as, matrix4 &matrix) const;
     211              : 
     212              :             void genvbo(vbocacheentry &vc);
     213              : 
     214              :             template<class T>
     215            0 :             void bindvbo(const AnimState *as, const part *p, const vbocacheentry &vc)
     216              :             {
     217            0 :                 const T *vverts = 0;
     218            0 :                 bindpos(ebuf, vc.vbuf, &vverts->pos, vertsize);
     219            0 :                 if(as->cur.anim & Anim_NoSkin)
     220              :                 {
     221            0 :                     if(enabletangents)
     222              :                     {
     223            0 :                         disabletangents();
     224              :                     }
     225            0 :                     if(p->alphatested())
     226              :                     {
     227            0 :                         bindtc(&vverts->tc, vertsize);
     228              :                     }
     229            0 :                     else if(enabletc)
     230              :                     {
     231            0 :                         disabletc();
     232              :                     }
     233              :                 }
     234              :                 else
     235              :                 {
     236            0 :                     bindtangents(&vverts->tangent, vertsize);
     237            0 :                     bindtc(&vverts->tc, vertsize);
     238              :                 }
     239            0 :                 if(enablebones)
     240              :                 {
     241            0 :                     disablebones();
     242              :                 }
     243            0 :             }
     244              : 
     245              :             void bindvbo(const AnimState *as, const part *p, const vbocacheentry &vc);
     246              :             /**
     247              :              * @brief Returns a pointer to this object.
     248              :              *
     249              :              * There is no appropriate pointer to pass other than itself, since
     250              :              * this is not a skeletal model
     251              :              */
     252              :             void *animkey() override final;
     253              :             void cleanup() override final;
     254              :             void preload() override final;
     255              :             void render(const AnimState *as, float, const vec &, const vec &, dynent *, part *p) override final;
     256              : 
     257              :             virtual bool load(const char *name, float smooth) = 0;
     258              :         };
     259              : 
     260              :         virtual vertmeshgroup *newmeshes() = 0;
     261              : 
     262              :         meshgroup *sharemeshes(const char *name, float smooth = 2);
     263              : 
     264              :         vertmodel(std::string name);
     265              : 
     266              :     private:
     267              :         meshgroup *loadmeshes(const char *name, float smooth = 2);
     268              : 
     269              : };
     270              : 
     271              : template<class MDL>
     272              : struct vertloader : modelloader<MDL, vertmodel>
     273              : {
     274            0 :     vertloader(std::string name) : modelloader<MDL, vertmodel>(name) {}
     275              : };
     276              : 
     277              : template<class MDL>
     278              : struct vertcommands : modelcommands<MDL>
     279              : {
     280              :     typedef struct MDL::vertmeshgroup meshgroup;
     281              :     typedef class  MDL::part part;
     282              :     typedef class  MDL::skin skin;
     283              : 
     284            1 :     static void loadpart(const char *model, const float *smooth)
     285              :     {
     286            1 :         if(!MDL::loading)
     287              :         {
     288            1 :             conoutf("not loading an %s", MDL::formatname());
     289            1 :             return;
     290              :         }
     291            0 :         std::string filename = std::format("{}/{}", MDL::dir, model);
     292            0 :         part &mdl = MDL::loading->addpart();
     293            0 :         if(mdl.index)
     294              :         {
     295            0 :             mdl.disablepitch();
     296              :         }
     297            0 :         mdl.meshes = MDL::loading->sharemeshes(path(filename).c_str(), *smooth > 0 ? std::cos(std::clamp(*smooth, 0.0f, 180.0f)/RAD) : 2);
     298            0 :         if(!mdl.meshes)
     299              :         {
     300            0 :             conoutf("could not load %s", filename.c_str());
     301              :         }
     302              :         else
     303              :         {
     304            0 :             mdl.initskins();
     305              :         }
     306            0 :     }
     307              : 
     308            1 :     static void settag(const char *tagname, const float *tx, const float *ty, const float *tz, const float *rx, const float *ry, const float *rz)
     309              :     {
     310            1 :         if(!MDL::loading || MDL::loading->parts.empty())
     311              :         {
     312            1 :             conoutf("not loading an %s", MDL::formatname());
     313            1 :             return;
     314              :         }
     315            0 :         const part &mdl = *static_cast<part *>(MDL::loading->parts.back());
     316            0 :         float cx = *rx ? std::cos(*rx/(2*RAD)) : 1,
     317            0 :               sx = *rx ? std::sin(*rx/(2*RAD)) : 0,
     318            0 :               cy = *ry ? std::cos(*ry/(2*RAD)) : 1,
     319            0 :               sy = *ry ? std::sin(*ry/(2*RAD)) : 0,
     320            0 :               cz = *rz ? std::cos(*rz/(2*RAD)) : 1,
     321            0 :               sz = *rz ? std::sin(*rz/(2*RAD)) : 0;
     322              :         //matrix m created from (matrix3 created from quat) + (vec) appended afterwards
     323            0 :         matrix4x3 m(static_cast<matrix3>(quat(sx*cy*cz - cx*sy*sz,
     324            0 :                                               cx*sy*cz + sx*cy*sz,
     325            0 :                                               cx*cy*sz - sx*sy*cz,
     326            0 :                                               cx*cy*cz + sx*sy*sz)),
     327            0 :                     vec(*tx, *ty, *tz));
     328              : 
     329            0 :         static_cast<meshgroup *>(mdl.meshes)->addtag(tagname, m);
     330              :     }
     331              : 
     332            0 :     static void setpitch(const float *pitchscale, const float *pitchoffset, const float *pitchmin, const float *pitchmax)
     333              :     {
     334            0 :         if(!MDL::loading || MDL::loading->parts.empty())
     335              :         {
     336            0 :             conoutf("not loading an %s", MDL::formatname());
     337            0 :             return;
     338              :         }
     339            0 :         part &mdl = *MDL::loading->parts.back();
     340            0 :         mdl.pitchscale = *pitchscale;
     341            0 :         mdl.pitchoffset = *pitchoffset;
     342            0 :         if(*pitchmin || *pitchmax)
     343              :         {
     344            0 :             mdl.pitchmin = *pitchmin;
     345            0 :             mdl.pitchmax = *pitchmax;
     346              :         }
     347              :         else
     348              :         {
     349            0 :             mdl.pitchmin = -360*std::fabs(mdl.pitchscale) + mdl.pitchoffset;
     350            0 :             mdl.pitchmax =  360*std::fabs(mdl.pitchscale) + mdl.pitchoffset;
     351              :         }
     352              :     }
     353              : 
     354            0 :     static void setanim(const char *anim, const int *frame, const int *range, const float *speed, const int *priority)
     355              :     {
     356            0 :         if(!MDL::loading || MDL::loading->parts.empty())
     357              :         {
     358            0 :             conoutf("not loading an %s", MDL::formatname());
     359            0 :             return;
     360              :         }
     361            0 :         std::vector<size_t> anims = findanims(anim);
     362            0 :         if(anims.empty())
     363              :         {
     364            0 :             conoutf("could not find animation %s", anim);
     365              :         }
     366              :         else
     367              :         {
     368            0 :             for(const size_t &i : anims)
     369              :             {
     370            0 :                 MDL::loading->parts.back()->setanim(0, i, *frame, *range, *speed, *priority);
     371              :             }
     372              :         }
     373            0 :     }
     374              : 
     375            1 :     vertcommands()
     376            1 :     {
     377            1 :         if(MDL::multiparted())
     378              :         {
     379            1 :             this->modelcommand(loadpart, "load", "sf"); //<fmt>load [model] [smooth]
     380              :         }
     381            1 :         this->modelcommand(settag, "tag", "sffffff"); //<fmt>tag [tagname] [tx] [ty] [tz] [rx] [ry] [rz]
     382            1 :         this->modelcommand(setpitch, "pitch", "ffff"); //<fmt>pitch [scale] [offset] [min] [max]
     383            1 :         if(MDL::cananimate())
     384              :         {
     385            0 :             this->modelcommand(setanim, "anim", "siiff"); //<fmt>anim [anim] [frame] [range] [speed] [priority]
     386              :         }
     387            1 :     }
     388              : };
     389              : 
     390              : #endif
        

Generated by: LCOV version 2.0-1