Advertisement
WeltEnSTurm

Untitled

Aug 1st, 2011
414
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.18 KB | None | 0 0
  1. // File: model.cpp, created on Jun 28, 2011 by WeltEnSTurm
  2.  
  3. #include "model.hpp"
  4. #include "../generic/vec.hpp"
  5. #include "../generic/decoder.hpp"
  6. #include <fstream>
  7.  
  8. namespace engine {
  9.     namespace decode {
  10.         struct obj_edge {
  11.                 obj_edge(): vertex(0), normal(0), uvw(0), texid(0){}
  12.                 vec*& operator[](uint i){
  13.                     switch(i){
  14.                         case 0:
  15.                             return vertex; break;
  16.                         case 1:
  17.                             return uvw; break;
  18.                         case 2:
  19.                             return normal; break;
  20.                         default:
  21.                             errexit("engine::decode::obj_edge[]: out of bounds");
  22.                             return vertex;
  23.                     }
  24.                 }
  25.                 vec* vertex;
  26.                 vec* normal;
  27.                 vec* uvw;
  28.                 uint texid;
  29.         };
  30.         struct obj_mtldata {
  31.                 uint texid;
  32.                 std::string name;
  33.                 texture* tex;
  34.         };
  35.  
  36.         struct obj_commandpair {
  37.                 std::string cmd;
  38.                 void(*func)(std::string&);
  39.         };
  40.         std::vector<obj_commandpair> obj_commandlist = {
  41.             {
  42.                 "f",
  43.                 [](std::string& c){
  44.  
  45.                 }
  46.             }
  47.         };
  48.  
  49.         bool obj(const std::string& name, model* target){
  50.             std::ifstream in(name.c_str(),std::ios::in);
  51.             if(!in.is_open())
  52.                 return false;
  53.  
  54.             std::vector<std::vector<vec> > obj_data;
  55.             obj_data.push_back(std::vector<vec>()); // vertices
  56.             obj_data.push_back(std::vector<vec>()); // normals
  57.             obj_data.push_back(std::vector<vec>()); // uvws
  58.             std::vector<obj_edge> obj_edges;
  59.             std::vector<obj_mtldata> obj_mtl;
  60.  
  61.             long line=0;
  62.             std::string warn = "Model \""+name+"\"";
  63.  
  64.             int TexID_Current = 0;
  65.             int TexID_Count = 0;
  66.  
  67.             while(in.good()){
  68.                 line++;
  69.                 std::string data;
  70.                 std::getline(in, data);
  71.                 data+='\n';
  72.                 while(data.find_first_of('#')<data.size()){
  73.                     long begin = data.find_first_of('#');
  74.                     long end = data.find_first_of('\n');
  75.                     if(end < (long)data.size() && end > begin)
  76.                         data.erase(begin, end-begin);
  77.                 }
  78.  
  79.                 while(data.find_last_of('\r')<data.size()){
  80.                     data[data.find_last_of('\r')] = '\n';
  81.                 }
  82.  
  83.                 std::string command="";
  84.  
  85.                 for(uint i=0; i<data.length(); i++){
  86.                     if(data[i]!=' ' && data[i]!='\t' && data[i] != '\n'){
  87.                         command+=data[i];
  88.                     }else if(command.length()){
  89.                         if(command=="v" || command=="vt" || command=="vn"){
  90.                             vec t;
  91.                             std::string n="";
  92.                             int filltarget=0;
  93.                             for(; i<data.length(); i++){
  94.                                 if(isnumberchar(data[i])){
  95.                                     n+=data[i];
  96.                                 }else if(n.length()){
  97.                                     t[filltarget++]=tonumber(n);
  98.                                     if(filltarget>2) break;
  99.                                     n="";
  100.                                 }
  101.                             }
  102.                             if(command=="v")
  103.                                 obj_data[0].push_back(t);
  104.                             else if(command=="vt")
  105.                                 obj_data[1].push_back(t);
  106.                             else if(command=="vn")
  107.                                 obj_data[2].push_back(t);
  108.                         }
  109.  
  110.                         else if(command=="f"){
  111.                             uint edges=0;
  112.                             for(; i<data.length(); i++){
  113.                                 if(isnumberchar(data[i])){
  114.                                     unsigned long end = data.find(' ', i);
  115.                                     if(end>=data.length()) end=data.find('\t', i);
  116.                                     if(end>=data.length()) end=data.find('\n', i);
  117.                                     if(end>=data.length()){
  118.                                         warning(warn+" may be corrupt");
  119.                                         return false;
  120.                                     }
  121.                                     edges++;
  122.                                     if(edges>3){                                            // we can only use triangles, so split all other
  123.                                         obj_edges.push_back(obj_edges[obj_edges.size()-3]); // primitives up. do this by copying the last two
  124.                                         obj_edges.push_back(obj_edges[obj_edges.size()-2]); // edges for each new one
  125.                                     }
  126.  
  127.                                     std::string num;
  128.                                     obj_edges.push_back(obj_edge());
  129.                                     obj_edge* edge = &obj_edges[obj_edges.size()-1];
  130.                                     edge->texid = TexID_Current;
  131.                                     uint mode=0;
  132.  
  133.                                     for(;i<=end;i++){
  134.                                         if(isnumberchar(data[i])){
  135.                                             num+=data[i];
  136.                                         }else if(num.length()){
  137.                                             uint idx=tonumber(num);
  138.                                             if(idx != tonumber(num) || idx<1 || idx>obj_data[mode].size()){
  139.                                                 warning(warn+" has dangerous "+(mode==0?"vertex":(mode==1?"uvw":"normal"))+
  140.                                                         " index ("+num+") at line "+line);
  141.                                                 return false;
  142.                                             } else {
  143.                                                 (*edge)[mode] = &obj_data[mode][idx-1];
  144.                                             }
  145.                                         }
  146.                                         if(data[i]=='/'){
  147.                                             num="";
  148.                                             mode++;
  149.                                             if(mode==3){
  150.                                                 warning(warn+" has dangerous face at line "+line);
  151.                                                 return false;
  152.                                             }
  153.                                         }
  154.                                     }
  155.                                     i--;
  156.                                 }
  157.                             }
  158.                         }
  159.  
  160.                         else if(command=="mtllib"){
  161.                             for(; i<data.length(); i++){
  162.                                 if(data[i]!=' '&& data[i] != '\t'){
  163.                                     uint end = data.find('\n',i);
  164.                                     if(end>=data.length()){
  165.                                         warning(warn+": could not open MTL file (command end not found)");
  166.                                         return false;
  167.                                     }
  168.                                     std::string mtlname = name.substr(0,name.find_last_of('/')+1)+data.substr(i, end-i);
  169.                                     data = data.substr(end);
  170.  
  171.                                     std::ifstream mtllib_f(mtlname.c_str(), std::ios::in);
  172.                                     if(!mtllib_f.is_open()){
  173.                                         warning(warn+": could not open mtl file ("+mtlname+")");
  174.                                         return false;
  175.                                     }
  176.  
  177.                                     std::string MatName_Cur;
  178.                                     GLint MaxTextures;
  179.                                     glGetIntegerv(GL_MAX_TEXTURE_UNITS, &MaxTextures);
  180.  
  181.                                     while(mtllib_f.good()){
  182.                                         std::string nl;
  183.                                         std::getline(mtllib_f, nl);
  184.                                         if(nl[0]=='#') continue;
  185.                                         nl+='\n';
  186.                                         std::string cmd="";
  187.                                         for(uint mi=0; mi<nl.size(); mi++){
  188.                                             if(nl[mi]!=' ' && nl[mi]!='\t'){
  189.                                                 cmd+=nl[mi];
  190.                                             }else if(cmd.length()){
  191.                                                 if(cmd=="newmtl"){
  192.                                                     for(;mi<nl.length();mi++)
  193.                                                         if(nl[mi]!=' '&&nl[mi]!='\t') break;
  194.                                                     MatName_Cur=nl.substr(mi,nl.size()-mi-1);
  195.                                                     mi=nl.size()-mi-1;
  196.                                                 }
  197.  
  198.                                                 else if(cmd=="map_Ka"){
  199.                                                     for(;mi<nl.length();mi++)
  200.                                                         if(nl[mi]!=' '&&nl[mi]!='\t') break;
  201.                                                     if(MaxTextures<(long)obj_mtl.size())
  202.                                                         warning(warn+" uses more textures than supported.");
  203.                                                     std::string path = nl.substr(mi,nl.size()-mi-1);
  204.                                                     texture* t = TextureManager::LoadTexture(path);
  205.                                                     if(t){
  206.                                                         obj_mtl.push_back(obj_mtldata());
  207.                                                         obj_mtldata* d = &obj_mtl[obj_mtl.size()-1];
  208.                                                         d->name = MatName_Cur;
  209.                                                         d->tex = t;
  210.                                                         d->texid = TexID_Count++;
  211.                                                         mi=nl.size()-mi-1;
  212.                                                     }
  213.                                                     else
  214.                                                         warning(warn+": failed to open "+path);
  215.                                                 }
  216.                                                 cmd="";
  217.                                             }
  218.                                         }
  219.                                     }
  220.                                     break;
  221.                                 }
  222.                             }
  223.                         }
  224.  
  225.                         else if(command=="usemtl"){
  226.                             for(; i<data.length(); i++){
  227.                                 if(data[i] != ' ' && data[i] != '\t'){
  228.                                     uint end = data.find('\n');
  229.                                     std::string name = data.substr(i,end-i);
  230.                                     data = data.substr(end);
  231.                                     bool found=false;
  232.                                     for(uint idx_matlist=0; idx_matlist<obj_mtl.size(); idx_matlist++){
  233.                                         if(obj_mtl[idx_matlist].name == name){
  234.                                             TexID_Current = obj_mtl[idx_matlist].texid;
  235.                                             found = true;
  236.                                             break;
  237.                                         }
  238.                                     }
  239.                                     if(!found){
  240.                                         warning(warn + " uses invalid material ("+name+") on line "+line);
  241.                                         return false;
  242.                                     }
  243.                                     break;
  244.                                 }
  245.                             }
  246.                         }
  247.  
  248.                         else{
  249.                             static std::vector<std::string> unknowncommands;
  250.                             bool has = false;
  251.                             for(long cmdi = unknowncommands.size()-1; cmdi>=0; cmdi--)
  252.                                 if(unknowncommands[cmdi] == command){
  253.                                     has = true;
  254.                                     break;
  255.                                 }
  256.                             if(!has){
  257.                                 warning(warn + " uses unknown command at line "+line+": "+command);
  258.                                 unknowncommands.push_back(command);
  259.                             }
  260.                             i = data.find_first_of('\n', i);
  261.                         }
  262.                         command="";
  263.                     }
  264.                 }
  265.             }
  266.             in.close();
  267.  
  268.             for(uint i=0; i<obj_mtl.size(); i++){
  269.                 glActiveTexture(GL_TEXTURE0+i);
  270.                 glBindTexture(GL_TEXTURE_2D, obj_mtl[i].tex->id);
  271.                 target->tex.push_back(obj_mtl[i].tex);
  272.             }
  273.  
  274.             target->data->Begin(GL_TRIANGLES, obj_edges.size(), obj_mtl.size());
  275.             for(uint i=0; i<obj_edges.size(); i++){
  276.                 if(obj_edges[i].uvw){
  277.                     vec u = *obj_edges[i].uvw;
  278.                     target->data->MultiTexCoord2f(obj_edges[i].texid, u.x, u.y);
  279.                 }
  280.                 if(obj_edges[i].normal){
  281.                     vec n = obj_edges[i].normal->ogl().Normalize();
  282.                     target->data->Normal3f(n.x,n.y,n.z);
  283.                 }else{
  284.                     target->data->Normal3f(0,1,0);
  285.                 }
  286.                 if(!obj_edges[i].vertex)
  287.                     warning(warn+": edge "+(i+1)+"uses invalid vertex");
  288.                 else{
  289.                     vec v = obj_edges[i].vertex->ogl();
  290.                     target->data->Vertex3f(v.x,v.y,v.z);
  291.                 }
  292.             }
  293.             target->data->End();
  294.             return true;
  295.         }
  296.     }
  297.  
  298.     model model::invalid;
  299.  
  300.     std::vector<model> ModelManager::ModelData;
  301.     ModelManager ModelManager::Manager;
  302.     ModelManager::~ModelManager(){
  303.         for(uint i=0; i<ModelData.size(); i++){
  304.             delete ModelData[i].data;
  305.             ModelData[i].data=0;
  306.         }
  307.     }
  308.     model* ModelManager::LoadModel(std::string name){
  309.         name = PATH_CONTENT + PATH_MODELS + name;
  310.         for(uint i=0; i<ModelData.size(); i++)
  311.             if(ModelData[i].path == name)
  312.                 return &ModelData[i];
  313.         ModelData.push_back(model());
  314.         model& m = ModelData[ModelData.size()-1];
  315.         m.SetData(name, new GLBatch);
  316.         if(decode::obj(name,&m))
  317.             return &m;
  318.  
  319.         ModelData.pop_back();
  320.         warning("Failed to load model \""+name+"\"");
  321.         return &model::invalid;
  322.     }
  323. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement