LCOV - code coverage report
Current view: top level - engine/model - obj.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 4 156 2.6 %
Date: 2024-11-22 05:07:59 Functions: 2 10 20.0 %

          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(vec(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 1.14