Нужна помощь в загрузке простых текстовых данных с C ++ - PullRequest
0 голосов
/ 27 ноября 2011

Мне нужна помощь при загрузке пользовательского формата файла в мою программу, созданную на 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

И это четверка ... (да; я знаю ... ужасный формат ... но это то, что я использую для игры для Android).

Я хочу создать функцию в c ++ для моего редактора (SDL + OpenGL для Windows), которая загружает эти файлы в данные ... К сожалению, хотя я знаю, как экспортировать этот формат с C ++, я не могу понять, как импортировать их ... я хочу использовать команды fstream ...

Если бы кто-то мог быстро написать простую версию, я был бы очень благодарен.

Я просто делаю следующее:

  • Найти текстовый файл из входной строки
  • прочитайте «NumVerts» и возьмите целое число, написанное после него
  • перебирает следующие (NumVerts * 3) строки и захватывает каждое число как число с плавающей запятой
  • цикл через следующие (NumVerts * 2) строки и захватить каждое число как число с плавающей запятой
  • перебирает следующие (NumVerts * 1) строки и захватывает каждое число как Int
  • (пропустить любую строку, начинающуюся с "//")
  • закрыть файл.

Спасибо за чтение, и любая помощь была бы очень полезна прямо сейчас ... или довольно простая ссылка, которая считывает строки из файлов и извлекает из них числа для помещения в память ...

Я действительно просто хочу закончить эту игру, и она становится очень напряженной, пытаясь найти полезные учебники.

Обновление: обновлен скрипт ... Я случайно забыл разделить 1 и 0 ...

Ответы [ 4 ]

2 голосов
/ 27 ноября 2011

Надеюсь, это поможет. Кстати, у вас неверное количество компонентов вершин - вам нужно 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;
}
1 голос
/ 27 ноября 2011

Надеюсь, это может помочь (минимальная проверка ошибок):

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;
}
0 голосов
/ 27 ноября 2011

Для ссылок о том, как сделать 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'.

0 голосов
/ 27 ноября 2011

использование плоского файла для этой цели может быть плохой идеей. это довольно хрупкий Я предпочитаю двоичный файл или файл с самоописанием (например, 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;
}); 
...