LCOV - code coverage report
Current view: top level - engine/model - obj.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 2.6 % 156 4
Test Date: 2025-02-18 06:21:28 Functions: 20.0 % 10 2

            Line data    Source code
       1              : /* obj.cpp: wavefront model support
       2              :  *
       3              :  * Libprimis supports the Wavefront (obj) model format for simple static models.
       4              :  * This file contains the implementation functions, while the class for the obj
       5              :  * model type is located in obj.h.
       6              :  */
       7              : #include "../libprimis-headers/cube.h"
       8              : #include "../../shared/geomexts.h"
       9              : #include "../../shared/glemu.h"
      10              : #include "../../shared/glexts.h"
      11              : #include "../../shared/stream.h"
      12              : 
      13              : #include <optional>
      14              : #include <memory>
      15              : 
      16              : #include "render/rendergl.h"
      17              : #include "render/rendermodel.h"
      18              : #include "render/renderwindow.h"
      19              : #include "render/shader.h"
      20              : #include "render/shaderparam.h"
      21              : #include "render/texture.h"
      22              : 
      23              : #include "interface/console.h"
      24              : #include "interface/control.h"
      25              : #include "interface/cs.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              : #include "obj.h"
      37              : 
      38              : #include "interface/console.h"
      39              : 
      40              : vertcommands<obj> obj::objcommands;
      41              : 
      42            0 : obj::obj(std::string name) : vertloader(name)
      43              : {
      44            0 : }
      45              : 
      46           59 : const char *obj::formatname()
      47              : {
      48           59 :     return "obj";
      49              : }
      50              : 
      51            1 : bool obj::cananimate()
      52              : {
      53            1 :     return false;
      54              : }
      55              : 
      56            0 : bool obj::flipy() const
      57              : {
      58            0 :     return true;
      59              : }
      60              : 
      61            0 : int obj::type() const
      62              : {
      63            0 :     return MDL_OBJ;
      64              : }
      65              : 
      66            0 : bool obj::skeletal() const
      67              : {
      68            0 :     return false;
      69              : }
      70              : 
      71            0 : bool obj::objmeshgroup::load(const char *filename, float smooth)
      72              : {
      73            0 :     int len = std::strlen(filename);
      74            0 :     if(len < 4 || strcasecmp(&filename[len-4], ".obj"))
      75              :     {
      76            0 :         return false;
      77              :     }
      78            0 :     stream *file = openfile(filename, "rb");
      79            0 :     if(!file)
      80              :     {
      81            0 :         return false;
      82              :     }
      83            0 :     name = filename;
      84            0 :     numframes = 1;
      85            0 :     std::array<std::vector<vec>, 3> attrib;
      86              :     char buf[512];
      87            0 :     std::unordered_map<ivec, uint> verthash;
      88            0 :     std::vector<vert> verts;
      89            0 :     std::vector<tcvert> tcverts;
      90            0 :     std::vector<tri> tris;
      91              : 
      92            0 :     string meshname = "";
      93            0 :     vertmesh *curmesh = nullptr;
      94            0 :     while(file->getline(buf, sizeof(buf)))
      95              :     {
      96            0 :         char *c = buf;
      97            0 :         while(std::isspace(*c))
      98              :         {
      99            0 :             c++;
     100              :         }
     101            0 :         switch(*c)
     102              :         {
     103            0 :             case '#':
     104              :             {
     105            0 :                 continue;
     106              :             }
     107            0 :             case 'v':
     108              :             {
     109            0 :                 if(std::isspace(c[1]))
     110              :                 {
     111            0 :                     parsevert(c, attrib[0]);
     112              :                 }
     113            0 :                 else if(c[1]=='t')
     114              :                 {
     115            0 :                     parsevert(c, attrib[1]);
     116              :                 }
     117            0 :                 else if(c[1]=='n')
     118              :                 {
     119            0 :                     parsevert(c, attrib[2]);
     120              :                 }
     121            0 :                 break;
     122              :             }
     123            0 :             case 'g':
     124              :             {
     125            0 :                 while(std::isalpha(*c))
     126              :                 {
     127            0 :                     c++;
     128              :                 }
     129            0 :                 while(std::isspace(*c))
     130              :                 {
     131            0 :                     c++;
     132              :                 }
     133            0 :                 char *name = c;
     134            0 :                 size_t namelen = std::strlen(name);
     135            0 :                 while(namelen > 0 && std::isspace(name[namelen-1]))
     136              :                 {
     137            0 :                     namelen--;
     138              :                 }
     139            0 :                 copystring(meshname, name, std::min(namelen+1, sizeof(meshname)));
     140            0 :                 if(curmesh)
     141              :                 {
     142            0 :                     flushmesh(*curmesh, verts, tcverts, tris, attrib[2], smooth);
     143              :                 }
     144            0 :                 curmesh = nullptr;
     145            0 :                 break;
     146              :             }
     147            0 :             case 'f':
     148              :             {
     149            0 :                 if(!curmesh)
     150              :                 {
     151              :                     //startmesh
     152            0 :                     vertmesh &m = *new vertmesh(meshname[0] ? std::string(meshname) : "", this);
     153            0 :                     meshes.push_back(&m);
     154            0 :                     curmesh = &m;
     155            0 :                     verthash.clear();
     156            0 :                     verts.clear();
     157            0 :                     tcverts.clear();
     158            0 :                     tris.clear();
     159              :                 }
     160            0 :                 std::optional<uint> v0 = std::nullopt,
     161            0 :                                     v1 = std::nullopt;
     162            0 :                 while(std::isalpha(*c))
     163              :                 {
     164            0 :                     c++;
     165              :                 }
     166              :                 for(;;)
     167              :                 {
     168            0 :                     while(std::isspace(*c))
     169              :                     {
     170            0 :                         c++;
     171              :                     }
     172            0 :                     if(!*c)
     173              :                     {
     174            0 :                         break;
     175              :                     }
     176            0 :                     ivec vkey(-1, -1, -1);
     177            0 :                     for(int i = 0; i < 3; ++i)
     178              :                     {
     179            0 :                         vkey[i] = std::strtol(c, &c, 10);
     180            0 :                         if(vkey[i] < 0)
     181              :                         {
     182            0 :                             vkey[i] = attrib[i].size() + vkey[i];
     183              :                         }
     184              :                         else
     185              :                         {
     186            0 :                             vkey[i]--;
     187              :                         }
     188            0 :                         if(!(attrib[i].size() > static_cast<uint>(vkey[i])))
     189              :                         {
     190            0 :                             vkey[i] = -1;
     191              :                         }
     192            0 :                         if(*c!='/')
     193              :                         {
     194            0 :                             break;
     195              :                         }
     196            0 :                         c++;
     197              :                     }
     198            0 :                     auto itr = verthash.find(vkey);
     199              :                     uint *index;
     200            0 :                     if(itr == verthash.end())
     201              :                     {
     202            0 :                         index = &verthash[vkey];
     203            0 :                         *index = verts.size();
     204            0 :                         vert v;
     205            0 :                         v.pos = vkey.x < 0 ? vec(0, 0, 0) : attrib[0][vkey.x];
     206            0 :                         v.pos = vec(v.pos.z, -v.pos.x, v.pos.y);
     207            0 :                         v.norm = vkey.z < 0 ? vec(0, 0, 0) : attrib[2][vkey.z];
     208            0 :                         v.norm = vec(v.norm.z, -v.norm.x, v.norm.y);
     209            0 :                         verts.push_back(v);
     210            0 :                         tcverts.push_back({vkey.y < 0 ? vec2(0, 0) : vec2(attrib[1][vkey.y].x, 1-attrib[1][vkey.y].y)});
     211              :                     }
     212              :                     else
     213              :                     {
     214            0 :                         index = &(*itr).second;
     215              :                     }
     216            0 :                     if(!v0)
     217              :                     {
     218            0 :                         v0 = *index;
     219              :                     }
     220            0 :                     else if(!v1)
     221              :                     {
     222            0 :                         v1 = *index;
     223              :                     }
     224              :                     else
     225              :                     {
     226            0 :                         tris.push_back({*index, v1.value(), v0.value()});
     227            0 :                         v1 = *index;
     228              :                     }
     229            0 :                 }
     230            0 :                 break;
     231              :             }
     232            0 :         }
     233              :     }
     234            0 :     if(curmesh)
     235              :     {
     236            0 :         flushmesh(*curmesh, verts, tcverts, tris, attrib[2], smooth);
     237              :     }
     238            0 :     delete file;
     239            0 :     return true;
     240            0 : }
     241              : 
     242            0 : void obj::objmeshgroup::parsevert(char *s, std::vector<vec> &out)
     243              : {
     244            0 :     out.emplace_back(0, 0, 0);
     245            0 :     vec &v = out.back();
     246            0 :     while(std::isalpha(*s))
     247              :     {
     248            0 :         s++;
     249              :     }
     250            0 :     for(int i = 0; i < 3; ++i)
     251              :     {
     252            0 :         v[i] = std::strtod(s, &s);
     253            0 :         while(std::isspace(*s))
     254              :         {
     255            0 :             s++;
     256              :         }
     257            0 :         if(!*s)
     258              :         {
     259            0 :             break;
     260              :         }
     261              :     }
     262            0 : }
     263              : 
     264            0 : void obj::objmeshgroup::flushmesh(vertmesh &curmesh,
     265              :                                   const std::vector<vert> &verts,
     266              :                                   const std::vector<tcvert> &tcverts,
     267              :                                   const std::vector<tri> &tris,
     268              :                                   const std::vector<vec> &attrib,
     269              :                                   float smooth)
     270              : {
     271            0 :     curmesh.numverts = verts.size();
     272            0 :     if(verts.size())
     273              :     {
     274            0 :         curmesh.verts = new vert[verts.size()];
     275            0 :         std::memcpy(curmesh.verts, verts.data(), verts.size()*sizeof(vert));
     276            0 :         curmesh.tcverts = new tcvert[verts.size()];
     277            0 :         std::memcpy(curmesh.tcverts, tcverts.data(), tcverts.size()*sizeof(tcvert));
     278              :     }
     279            0 :     curmesh.numtris = tris.size();
     280            0 :     if(tris.size())
     281              :     {
     282            0 :         curmesh.tris = new tri[tris.size()];
     283            0 :         std::memcpy(curmesh.tris, tris.data(), tris.size()*sizeof(tri));
     284              :     }
     285            0 :     if(attrib.empty())
     286              :     {
     287            0 :         if(smooth <= 1)
     288              :         {
     289            0 :             curmesh.smoothnorms(smooth);
     290              :         }
     291              :         else
     292              :         {
     293            0 :             curmesh.buildnorms();
     294              :         }
     295              :     }
     296            0 :     curmesh.calctangents();
     297            0 : }
     298              : 
     299            0 : bool obj::loaddefaultparts()
     300              : {
     301            0 :     part &mdl = addpart();
     302            0 :     std::string pname = parentdir(modelname().c_str());
     303            0 :     DEF_FORMAT_STRING(name1, "%s%s/tris.obj", modelpath.c_str(), modelname().c_str());
     304            0 :     mdl.meshes = sharemeshes(path(name1));
     305            0 :     if(!mdl.meshes)
     306              :     {
     307            0 :         DEF_FORMAT_STRING(name2, "%s%s/tris.obj", modelpath.c_str(), pname.c_str());    // try obj in parent folder (vert sharing)
     308            0 :         mdl.meshes = sharemeshes(path(name2));
     309            0 :         if(!mdl.meshes)
     310              :         {
     311            0 :             return false;
     312              :         }
     313              :     }
     314              :     Texture *tex, *masks;
     315            0 :     loadskin(modelname(), pname, tex, masks);
     316            0 :     mdl.initskins(tex, masks);
     317            0 :     if(tex==notexture)
     318              :     {
     319            0 :         conoutf("could not load model skin for %s", name1);
     320              :     }
     321            0 :     return true;
     322            0 : }
        

Generated by: LCOV version 2.0-1