390 lines
11 KiB
C++
390 lines
11 KiB
C++
#include "TextModel.h"
|
||
#include <regex>
|
||
#include <string>
|
||
#include <fstream>
|
||
#include <iostream>
|
||
#include <sstream>
|
||
|
||
namespace ZL
|
||
{
|
||
|
||
|
||
VertexDataStruct LoadFromTextFile(const std::string& fileName, const std::string& ZIPFileName)
|
||
{
|
||
VertexDataStruct result;
|
||
std::ifstream filestream;
|
||
std::istringstream zipStream;
|
||
|
||
if (!ZIPFileName.empty())
|
||
{
|
||
std::vector<char> fileData = readFileFromZIP(fileName, ZIPFileName);
|
||
std::string fileContents(fileData.begin(), fileData.end());
|
||
zipStream.str(fileContents);
|
||
}
|
||
else
|
||
{
|
||
filestream.open(fileName);
|
||
}
|
||
|
||
// Создаем ссылку f на нужный поток – после этого код ниже остается без изменений
|
||
std::istream& f = (!ZIPFileName.empty()) ? static_cast<std::istream&>(zipStream) : static_cast<std::istream&>(filestream);
|
||
|
||
|
||
//Skip first 5 lines
|
||
std::string tempLine;
|
||
|
||
std::getline(f, tempLine);
|
||
|
||
static const std::regex pattern_count(R"(\d+)");
|
||
static const std::regex pattern_float(R"([-]?\d+\.\d+)");
|
||
static const std::regex pattern_int(R"([-]?\d+)");
|
||
|
||
|
||
std::smatch match;
|
||
|
||
int numberVertices;
|
||
|
||
if (std::regex_search(tempLine, match, pattern_count)) {
|
||
std::string number_str = match.str();
|
||
numberVertices = std::stoi(number_str);
|
||
}
|
||
else {
|
||
throw std::runtime_error("No number found in the input string.");
|
||
}
|
||
|
||
std::vector<Vector3f> vertices;
|
||
|
||
vertices.resize(numberVertices);
|
||
for (int i = 0; i < numberVertices; i++)
|
||
{
|
||
std::getline(f, tempLine);
|
||
|
||
std::vector<float> floatValues;
|
||
|
||
auto b = tempLine.cbegin();
|
||
auto e = tempLine.cend();
|
||
while (std::regex_search(b, e, match, pattern_float)) {
|
||
floatValues.push_back(std::stof(match.str()));
|
||
b = match.suffix().first;
|
||
}
|
||
|
||
vertices[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||
}
|
||
|
||
std::cout << "UV Coordinates" << std::endl;
|
||
|
||
std::getline(f, tempLine); //===UV Coordinates:
|
||
|
||
std::getline(f, tempLine); //triangle count
|
||
int numberTriangles;
|
||
|
||
if (std::regex_search(tempLine, match, pattern_count)) {
|
||
std::string number_str = match.str();
|
||
numberTriangles = std::stoi(number_str);
|
||
}
|
||
else {
|
||
throw std::runtime_error("No number found in the input string.");
|
||
}
|
||
|
||
|
||
// Now process UVs
|
||
std::vector<std::array<Vector2f, 3>> uvCoords;
|
||
|
||
uvCoords.resize(numberTriangles);
|
||
|
||
for (int i = 0; i < numberTriangles; i++)
|
||
{
|
||
std::getline(f, tempLine); //Face 0
|
||
|
||
int uvCount;
|
||
std::getline(f, tempLine);
|
||
if (std::regex_search(tempLine, match, pattern_count)) {
|
||
std::string number_str = match.str();
|
||
uvCount = std::stoi(number_str);
|
||
}
|
||
else {
|
||
throw std::runtime_error("No number found in the input string.");
|
||
}
|
||
|
||
if (uvCount != 3)
|
||
{
|
||
throw std::runtime_error("more than 3 uvs");
|
||
}
|
||
|
||
std::vector<float> floatValues;
|
||
|
||
for (int j = 0; j < 3; j++)
|
||
{
|
||
std::getline(f, tempLine); //UV <Vector (-0.3661, -1.1665)>
|
||
|
||
auto b = tempLine.cbegin();
|
||
auto e = tempLine.cend();
|
||
floatValues.clear();
|
||
while (std::regex_search(b, e, match, pattern_float)) {
|
||
floatValues.push_back(std::stof(match.str()));
|
||
b = match.suffix().first;
|
||
}
|
||
|
||
if (floatValues.size() != 2)
|
||
{
|
||
throw std::runtime_error("more than 2 uvs---");
|
||
}
|
||
|
||
uvCoords[i][j] = Vector2f{ floatValues[0],floatValues[1] };
|
||
}
|
||
}
|
||
|
||
std::cout << "Normals go" << std::endl;
|
||
|
||
std::getline(f, tempLine); //===Normals:
|
||
|
||
|
||
std::vector<Vector3f> normals;
|
||
|
||
normals.resize(numberVertices);
|
||
for (int i = 0; i < numberVertices; i++)
|
||
{
|
||
std::getline(f, tempLine);
|
||
|
||
std::vector<float> floatValues;
|
||
|
||
auto b = tempLine.cbegin();
|
||
auto e = tempLine.cend();
|
||
while (std::regex_search(b, e, match, pattern_float)) {
|
||
floatValues.push_back(std::stof(match.str()));
|
||
b = match.suffix().first;
|
||
}
|
||
|
||
normals[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||
}
|
||
|
||
std::cout << "Triangles go:" << std::endl;
|
||
|
||
std::getline(f, tempLine); //===Triangles: 3974
|
||
|
||
|
||
std::vector<std::array<int, 3>> triangles;
|
||
|
||
triangles.resize(numberTriangles);
|
||
for (int i = 0; i < numberTriangles; i++)
|
||
{
|
||
std::getline(f, tempLine);
|
||
|
||
std::vector<int> intValues;
|
||
|
||
auto b = tempLine.cbegin();
|
||
auto e = tempLine.cend();
|
||
while (std::regex_search(b, e, match, pattern_int)) {
|
||
intValues.push_back(std::stoi(match.str()));
|
||
b = match.suffix().first;
|
||
}
|
||
|
||
triangles[i] = { intValues[0], intValues[1], intValues[2] };
|
||
}
|
||
|
||
|
||
std::cout << "Process vertices" << std::endl;
|
||
|
||
|
||
|
||
// Now let's process vertices
|
||
|
||
for (int i = 0; i < numberTriangles; i++)
|
||
{
|
||
|
||
result.PositionData.push_back(vertices[triangles[i][0]]);
|
||
result.PositionData.push_back(vertices[triangles[i][1]]);
|
||
result.PositionData.push_back(vertices[triangles[i][2]]);
|
||
|
||
/*
|
||
result.NormalData.push_back(normals[triangles[i][0]]);
|
||
result.NormalData.push_back(normals[triangles[i][1]]);
|
||
result.NormalData.push_back(normals[triangles[i][2]]);
|
||
*/
|
||
result.TexCoordData.push_back(uvCoords[i][0]);
|
||
result.TexCoordData.push_back(uvCoords[i][1]);
|
||
result.TexCoordData.push_back(uvCoords[i][2]);
|
||
|
||
}
|
||
|
||
//Swap from Blender format to OpenGL format
|
||
for (int i = 0; i < result.PositionData.size(); i++)
|
||
{
|
||
Vector3f tempVec = result.PositionData[i];
|
||
result.PositionData[i].v[0] = tempVec.v[1];
|
||
result.PositionData[i].v[1] = tempVec.v[2];
|
||
result.PositionData[i].v[2] = tempVec.v[0];
|
||
|
||
/*
|
||
tempVec = result.NormalData[i];
|
||
result.NormalData[i].v[0] = tempVec.v[1];
|
||
result.NormalData[i].v[1] = tempVec.v[2];
|
||
result.NormalData[i].v[2] = tempVec.v[0];*/
|
||
|
||
}
|
||
|
||
return result;
|
||
|
||
}
|
||
|
||
VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName)
|
||
{
|
||
VertexDataStruct result;
|
||
std::ifstream filestream;
|
||
std::istringstream zipStream;
|
||
|
||
// --- 1. Открытие потока (без изменений) ---
|
||
if (!ZIPFileName.empty())
|
||
{
|
||
std::vector<char> fileData = readFileFromZIP(fileName, ZIPFileName);
|
||
std::string fileContents(fileData.begin(), fileData.end());
|
||
zipStream.str(fileContents);
|
||
}
|
||
else
|
||
{
|
||
filestream.open(fileName);
|
||
if (!filestream.is_open()) {
|
||
throw std::runtime_error("Failed to open file: " + fileName);
|
||
}
|
||
}
|
||
|
||
std::istream& f = (!ZIPFileName.empty()) ? static_cast<std::istream&>(zipStream) : static_cast<std::istream&>(filestream);
|
||
|
||
std::string tempLine;
|
||
std::smatch match;
|
||
|
||
// Обновленные регулярки
|
||
// pattern_float стал чуть надежнее для чисел вида "0" или "-1" без точки, если вдруг Python округлит до int
|
||
static const std::regex pattern_count(R"(\d+)");
|
||
static const std::regex pattern_float(R"([-]?\d+(\.\d+)?)");
|
||
static const std::regex pattern_int(R"([-]?\d+)");
|
||
|
||
// --- 2. Парсинг Вершин (Pos + Norm + UV) ---
|
||
|
||
// Ищем заголовок ===Vertices
|
||
while (std::getline(f, tempLine)) {
|
||
if (tempLine.find("===Vertices") != std::string::npos) break;
|
||
}
|
||
|
||
int numberVertices = 0;
|
||
if (std::regex_search(tempLine, match, pattern_count)) {
|
||
numberVertices = std::stoi(match.str());
|
||
}
|
||
else {
|
||
throw std::runtime_error("Vertices header not found or invalid.");
|
||
}
|
||
|
||
// Временные буферы для хранения "уникальных" вершин перед разверткой по индексам
|
||
std::vector<Vector3f> tempPositions(numberVertices);
|
||
std::vector<Vector3f> tempNormals(numberVertices);
|
||
std::vector<Vector2f> tempUVs(numberVertices);
|
||
|
||
for (int i = 0; i < numberVertices; i++)
|
||
{
|
||
std::getline(f, tempLine);
|
||
// Строка вида: V 0: Pos(x, y, z) Norm(x, y, z) UV(u, v)
|
||
|
||
std::vector<float> floatValues;
|
||
floatValues.reserve(8); // Ожидаем ровно 8 чисел (3 pos + 3 norm + 2 uv)
|
||
|
||
auto b = tempLine.cbegin();
|
||
auto e = tempLine.cend();
|
||
while (std::regex_search(b, e, match, pattern_float)) {
|
||
floatValues.push_back(std::stof(match.str()));
|
||
b = match.suffix().first;
|
||
}
|
||
|
||
// Проверка целостности строки (ID вершины regex может поймать первым, но нас интересуют данные)
|
||
// Обычно ID идет первым (0), потом 3+3+2 float. Итого 9 чисел, если считать ID.
|
||
// Ваш Python пишет "V 0:", regex поймает 0. Потом 8 флоатов.
|
||
|
||
// Если regex ловит ID вершины как float (что вероятно), нам нужно смещение.
|
||
// ID - floatValues[0]
|
||
// Pos - [1], [2], [3]
|
||
// Norm - [4], [5], [6]
|
||
// UV - [7], [8]
|
||
|
||
if (floatValues.size() < 9) {
|
||
throw std::runtime_error("Malformed vertex line at index " + std::to_string(i));
|
||
}
|
||
|
||
tempPositions[i] = Vector3f{ floatValues[1], floatValues[2], floatValues[3] };
|
||
tempNormals[i] = Vector3f{ floatValues[4], floatValues[5], floatValues[6] };
|
||
tempUVs[i] = Vector2f{ floatValues[7], floatValues[8] };
|
||
}
|
||
|
||
// --- 3. Парсинг Треугольников (Индексов) ---
|
||
|
||
// Пропускаем пустые строки до заголовка треугольников
|
||
while (std::getline(f, tempLine)) {
|
||
if (tempLine.find("===Triangles") != std::string::npos) break;
|
||
}
|
||
|
||
int numberTriangles = 0;
|
||
if (std::regex_search(tempLine, match, pattern_count)) {
|
||
numberTriangles = std::stoi(match.str());
|
||
}
|
||
else {
|
||
throw std::runtime_error("Triangles header not found.");
|
||
}
|
||
|
||
// Резервируем память в result, чтобы избежать лишних аллокаций
|
||
result.PositionData.reserve(numberTriangles * 3);
|
||
result.NormalData.reserve(numberTriangles * 3);
|
||
result.TexCoordData.reserve(numberTriangles * 3);
|
||
|
||
for (int i = 0; i < numberTriangles; i++)
|
||
{
|
||
std::getline(f, tempLine);
|
||
// Строка вида: Tri: 0 1 2
|
||
|
||
std::vector<int> indices;
|
||
indices.reserve(3);
|
||
|
||
auto b = tempLine.cbegin();
|
||
auto e = tempLine.cend();
|
||
while (std::regex_search(b, e, match, pattern_int)) {
|
||
indices.push_back(std::stoi(match.str()));
|
||
b = match.suffix().first;
|
||
}
|
||
|
||
if (indices.size() != 3) {
|
||
throw std::runtime_error("Malformed triangle line at index " + std::to_string(i));
|
||
}
|
||
|
||
// --- 4. Заполнение VertexDataStruct (Flattening) ---
|
||
// Берем данные из временных буферов по индексам и кладем в итоговый массив
|
||
|
||
for (int k = 0; k < 3; k++) {
|
||
int idx = indices[k];
|
||
result.PositionData.push_back(tempPositions[idx]);
|
||
result.NormalData.push_back(tempNormals[idx]);
|
||
result.TexCoordData.push_back(tempUVs[idx]);
|
||
}
|
||
}
|
||
|
||
// --- 5. Конвертация координат (Blender -> OpenGL/Engine) ---
|
||
// Сохраняем вашу логику смены осей: X->Z, Y->X, Z->Y
|
||
|
||
for (size_t i = 0; i < result.PositionData.size(); i++)
|
||
{
|
||
Vector3f originalPos = result.PositionData[i];
|
||
result.PositionData[i].v[0] = originalPos.v[1]; // New X = Old Y
|
||
result.PositionData[i].v[1] = originalPos.v[2]; // New Y = Old Z
|
||
result.PositionData[i].v[2] = originalPos.v[0]; // New Z = Old X
|
||
|
||
Vector3f originalNorm = result.NormalData[i];
|
||
result.NormalData[i].v[0] = originalNorm.v[1];
|
||
result.NormalData[i].v[1] = originalNorm.v[2];
|
||
result.NormalData[i].v[2] = originalNorm.v[0];
|
||
}
|
||
|
||
std::cout << "Model loaded: " << numberVertices << " verts, " << numberTriangles << " tris." << std::endl;
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
|
||
} |