LCOV - code coverage report
Current view: top level - engine/model - vertmodel.h (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 12.1 % 132 16
Test Date: 2025-02-18 06:21:28 Functions: 23.1 % 13 3

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

Generated by: LCOV version 2.0-1