space-game001/TextModel.cpp
Vladislav Khorev b45d9300bd New version
2025-11-30 22:46:42 +03:00

390 lines
11 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
}