2011-11-27 43 views
0

我需要幫助加載自定義文件格式到我的程序在C++中... 我知道有一個簡單的方法做到這一點,但我認爲我使用 錯誤的術語來尋找它的在線...需要幫助加載簡單的文本數據與c + +

我的3D對象的自定義格式如下:

NumVerts 6 
//verts (float) 
-1 
-1 
0 
1 
-1 
0 
-1 
1 
0 
1 
-1 
0 
1 
1 
0 
-1 
1 
0 
//texture (float) 
0 
0 
1 
0 
0 
1 
1 
0 
1 
1 
0 
1 
//index (int) 
0 
1 
2 
1 
3 
2 

而且爲四...(贊成票;我知道......太可怕了......格式,但這就是我用於安卓遊戲的原因)。

我想爲我的編輯器(SDL + OpenGL for windows)製作一個函數,將這些文件加載​​到數據中......不幸的是,儘管我知道如何用C++導出這種格式,但我無法弄清楚導入他們...我希望使用fstream命令...

如果有人能夠快速寫出一個簡單的版本,我會非常感激。

我只是把它做到以下幾點:從輸入字符串

  • 查找文本文件
  • 讀「NumVerts」,並抓住它
  • 通過下一個循環之後寫的整數(NumVerts * 3)線並抓住每個號碼爲float
  • 循環雖然下一個(NumVerts * 2)線和抓住每個號碼爲float
  • 遍歷下一(NumVerts * 1)線並抓住每個號碼作爲一個Int
  • (跳過以「//」開頭的任何行)
  • 關閉文件。

謝謝您的閱讀和任何幫助將是非常不錯的,現在......還是relivent鏈接,很簡單,並讀取從他們的文件和爭奪數字的字符串被放置到內存...

我真的只想完成這個遊戲,它試圖找到有用的教程變得非常緊張。

更新:更新腳本...我不小心忘了單獨的1只0 ...

+0

如果這是一個嚴重的項目,你應該考慮一個更有效的二進制格式(也許像NetCDF)。 –

+0

@KerrekSB關於「嚴肅的項目」,我有點不願意使用二進制格式,因爲它們不一定是可移植的(endianess,浮點格式)。例如,COLLADA相當「嚴肅」,仍然將頂點存儲爲字符串。 – zerm

+0

@zerm:像NetCDF這樣的自描述功能的設計考慮到了可移植性......無論如何,序列化可移植性僅僅是衡量作者記錄格式的能力的尺度! –

回答

2

希望這有助於。順便說一句,你有錯誤的頂點組件數量 - 你需要18他們。

#include <algorithm> 
#include <exception> 
#include <fstream> 
#include <iostream> 
#include <string> 
#include <vector> 

#include <boost/algorithm/string/trim.hpp> 
#include <boost/lexical_cast.hpp> 
using boost::lexical_cast; 

int load_3d_object(const std::string& filename, 
        std::vector<float>& vertComponents, 
        std::vector<float>& texComponents, 
        std::vector<int>& indices) 
{ 
    std::ifstream fs(filename.c_str()); 
    std::string line; 
    if(!std::getline(fs, line)) 
    { 
     throw std::runtime_error("The input file is empty"); 
    } 

    if(line.substr(0,8) != "NumVerts") 
    { 
     throw std::runtime_error("The first line must start with NumVerts"); 
    } 

    // Extract the number of vertices. 
    int numVerts = lexical_cast<int>(line.substr(line.find(' ') + 1)); 

    // Read in the vertex components, texture components and indices. 
    while(std::getline(fs, line)) 
    { 
     boost::trim(line); 
     if(line.substr(0,2) == "//") continue; 

     if((int)vertComponents.size() < numVerts * 3)  vertComponents.push_back(lexical_cast<float>(line)); 
     else if((int)texComponents.size() < numVerts * 2) texComponents.push_back(lexical_cast<float>(line)); 
     else            indices.push_back(lexical_cast<int>(line)); 
    } 

    return numVerts; 
} 

int main() 
{ 
    std::vector<float> vertComponents; 
    std::vector<float> texComponents; 
    std::vector<int> indices; 
    try 
    { 
     int numVerts = load_3d_object("input.txt", vertComponents, texComponents, indices); 
    } 
    catch(std::exception& e) 
    { 
     std::cout << e.what() << '\n'; 
    } 
    return 0; 
} 
+0

我只是忽略了這個,或者你錯過了正確處理評論?你應該添加類似於'if(line.find(「//」)!= 0)lines.push_back(line);' – zerm

+0

@zerm:在第二個版本中,我只是跳過以//開頭的行很好,因爲我之前修剪過它們)。我並沒有聲稱這是我爲生產代碼編寫的 - 這絕對不是。第一個版本通過假設文件格式是每個示例來說明註釋行 - 並相應地設置開始索引。 –

+0

@Stuart Golodetz:謝謝你指出事實上沒有18個變量......我只是很快地輸入了它,並沒有想到要仔細檢查...... (我有點累了)。我會看看我是否可以根據你的代碼寫出一些東西......非常感謝。看起來完全像我所需要的。感謝您向我解釋代碼。 – Kalisme

1

希望這可以幫助(最小錯誤檢查):

int _get_num_verts_value(std::ifstream& a_in) 
{ 
    char buf[128]; 
    int result = -1; 
    a_in.getline(buf, sizeof(buf)); 
    while (a_in.good()) 
    { 
     if (a_in.gcount() > 9) 
     { 
      string s(buf); 
      if (0 == s.find("NumVerts ")) 
      { 
       result = atoi(s.substr(8).c_str()); 
       break; 
      } 
     } 
     a_in.getline(buf, sizeof(buf)); 
    } 
    return result; 
} 

template <typename T> 
void _get_values(std::ifstream& a_in, std::vector<T>& a_values) 
{ 
    char buf[128]; 
    a_in.getline(buf, sizeof(buf)); 
    int i = 0; 
    while (a_in.good()) 
    { 
     string line(buf); 
     if (0 != line.find("//")) 
     { 
      a_values[i++] = boost::lexical_cast<T>(line); 
      // All read ? 
      if (i == a_values.capacity()) 
      { 
       break; 
      } 
     } 
     a_in.getline(buf, sizeof(buf)); 
    } 
} 

int main(int /*a_argc*/, char** /*a_argv*/) 
{ 
    ifstream in("test.txt"); 
    const int num_verts_value = _get_num_verts_value(in); 

    std::vector<float> verts(num_verts_value * 3); 
    _get_values<float>(in, verts); 

    std::vector<float> textures(num_verts_value * 2); 
    _get_values<float>(in, textures); 

    std::vector<int> indexes(num_verts_value); 
    _get_values<int>(in, indexes); 

    in.close(); 

    return 0; 
} 
+1

爲什麼'getline'進入固定大小的緩衝區時'std :: getline'可以讓你閱讀直接進入'std :: string'? :) –

+0

@Stuart,你確定?只是重新檢查文檔,並沒有'getline()'採用'std :: string',我只是在VC10中試過,並且編譯失敗。 – hmjd

+0

@stuart,你是對的。我以爲你指的是'ifstream :: getline()'。在這裏使用'std :: getline()'會更好,謝謝。 – hmjd

0

使用平面文件用於此目的可能是一個壞主意。它非常脆弱。我更喜歡二進制文件或自我描述的文件(例如xml)。

std::ifstream in("in"); 
char buf[256]; 
std::string line; 
int NumVerts; 
in >> buf >> NumVerts; 
std::vector<float> verts(NumVerts * 3); 
std::getline(in, line);//read the rest of the line 
std::getline(in, line);//skip the comment line 
std::for_each(verts.begin(), verts.end(), [&in](float& par){ 
    in >> par; 
}); 
std::vector<float> texture(NumVerts * 2); 
std::getline(in, line);//read the rest of the line 
std::getline(in, line);//skip the comment line 
std::for_each(texture.begin(), texture.end(), [&in](float& par){ 
    in >> par; 
}); 
std::vector<int> index(NumVerts); 
std::getline(in, line);//read the rest of the line 
std::getline(in, line);//skip the comment line 
std::for_each(index.begin(), index.end(), [&in](int& par){ 
    in >> par; 
}); 
0

有關如何DIY鏈接:

示例代碼:

#include <string> 
#include <iostream> // needed for printing stuff out 
#include <fstream> // Needed to read the file 
#include <stdexcept> 
#include <vector> 

using namespace std; 

struct Vertice { 
    double x,y,z; // 3 part stuff to read 
    double a,b; // 2 part stuff to read 
    int i;  // 1 int thing to read 
}; 

/// Reads a number ignoring comment lines (and any other line that isn't a number) 
template <typename T> 
T readNumber(istream& data) { 
    char lastChar; 
    while (data.good()) { 
     data >> lastChar; // Don't use peek as that won't skip whitespace 
     data.putback(lastChar); 
     if (((lastChar >= '0') && (lastChar <= '9')) || (lastChar == '-')) { 
      // If we're looking at a number read and return it 
      T result; 
      data >> result; 
      return result; 
     } else { 
      // If it's not part of a number .. assume it's a comment line and skip the whole line 
      string commentLine; 
      getline(data, commentLine); 
      // TODO: Maybe just skip '//' lines and throw an exception for everything else.. 
     } 
    } 
    throw exception("Couldn't read file"); 
} 

double readDouble(istream& data) { return readNumber<double>(data); } 
int readInt(istream& data) { return readNumber<int>(data); } 

int main(int argc, char** argv) { 
    if (argc != 2) 
     cout << "Usage: " << argv[0] << " [DATA_FILE_NAME]" << endl; 
    else { 
     fstream data(argv[1], ios_base::in); 
     data >> skipws; // Skip whitespace 
     string lastString; 
     long numVerts = -1; 
     // Read in words ignoring everything until we hit a 'NumVerts' 
     while (numVerts < 0) { 
      data >> lastString; 
      if (lastString == "NumVerts") 
       data >> numVerts; 
     } 
     // We know how many to get now 
     typedef vector<Vertice> Verts; 
     Verts verts(numVerts); 
     // Read in the triples 
     for (Verts::iterator i=verts.begin(); i != verts.end(); ++i) { 
      i->x = readDouble(data); 
      i->y = readDouble(data); 
      i->z = readDouble(data); 
     } 
     // Read in the pairs (some other data) 
     for (Verts::iterator i=verts.begin(); i != verts.end(); ++i) { 
      i->a = readDouble(data); 
      i->b = readDouble(data); 
     } 
     // Read in the single integer value 
     for (Verts::iterator i=verts.begin(); i != verts.end(); ++i) { 
      i->i = readInt(data); 
     } 
     // Print out all we found 
     for (Verts::iterator i=verts.begin(); i != verts.end(); ++i) { 
      cout << "Vertice" << endl 
       << " x: " << i->x << endl 
       << " y: " << i->y << endl 
       << " z: " << i->z << endl 
       << " a: " << i->a << endl 
       << " b: " << i->b << endl 
       << " i: " << i->i << endl 
       << endl; 
     } 

    } 

} 

示例代碼在提供的文件上拋出錯誤,因爲沒有足夠的數據來填充'NumVerts'。