#include "TextModel.h" #include #include #include #include #include #ifdef __ANDROID__ #include #endif namespace ZL { static std::unordered_map s_meshCache; static std::string CacheKey(const std::string& fileName) { if (fileName.size() > 4 && fileName.compare(fileName.size() - 4, 4, ".bin") == 0) return fileName.substr(0, fileName.size() - 4); return fileName; } VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName) { std::string key = CacheKey(fileName); auto it = s_meshCache.find(key); if (it != s_meshCache.end()) return it->second; VertexDataStruct result; std::istringstream f; // --- 1. Открытие потока (без изменений) --- if (!ZIPFileName.empty()) { std::vector fileData = readFileFromZIP(fileName, ZIPFileName); std::string fileContents(fileData.begin(), fileData.end()); f.str(fileContents); } else { #ifdef __ANDROID__ // Для Android используем SDL_RWops для чтения файлов __android_log_print(ANDROID_LOG_INFO, "TextModel", "LoadFromTextFile02 called for Android: %s", fileName.c_str()); #endif // Читаем файл с помощью readTextFile std::string fileContent = readTextFile(fileName); if (fileContent.empty()) { #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_ERROR, "TextModel", "Failed to read file: %s", fileName.c_str()); #endif throw std::runtime_error("Failed to read file: " + fileName); } #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_INFO, "TextModel", "File read successfully, size: %zu", fileContent.size()); #endif f.str(fileContent); } 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+([eE][-+]?\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 { std::cout << "Vertices header not found or invalid: " << tempLine << std::endl; throw std::runtime_error("Vertices header not found or invalid."); } // Временные буферы для хранения "уникальных" вершин перед разверткой по индексам std::vector tempPositions(numberVertices); std::vector tempNormals(numberVertices); std::vector 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 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) { std::cout << "Malformed vertex line at index " << i << ": " << tempLine << std::endl; 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 { std::cout << "Triangles header not found or invalid: " << tempLine << std::endl; 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 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) { std::cout << "Malformed triangle line at index " << i << ": " << tempLine << std::endl; 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](0) = originalPos(1); // New X = Old Y result.PositionData[i](1) = originalPos(2); // New Y = Old Z result.PositionData[i](2) = originalPos(0); // New Z = Old X Vector3f originalNorm = result.NormalData[i]; result.NormalData[i](0) = originalNorm(1); result.NormalData[i](1) = originalNorm(2); result.NormalData[i](2) = originalNorm(0); } std::cout << "Model loaded: " << numberVertices << " verts, " << numberTriangles << " tris." << std::endl; s_meshCache[key] = result; return result; } VertexDataStruct LoadModelFromBinFile(const std::string& fileName, const std::string& ZIPFileName) { std::string key = CacheKey(fileName); auto it = s_meshCache.find(key); if (it != s_meshCache.end()) return it->second; std::vector fileData = !ZIPFileName.empty() ? readFileFromZIP(fileName, ZIPFileName) : readFile(fileName); if (fileData.size() < 16) throw std::runtime_error("Binary mesh file is too short: " + fileName); const char* ptr = fileData.data(); if (ptr[0] != 'B' || ptr[1] != 'S' || ptr[2] != 'M' || ptr[3] != 'F') throw std::runtime_error("Invalid magic bytes in binary mesh file: " + fileName); ptr += 4; uint32_t version = *reinterpret_cast(ptr); ptr += 4; if (version != 1) throw std::runtime_error("Unsupported binary mesh version " + std::to_string(version) + ": " + fileName); uint32_t numVertices = *reinterpret_cast(ptr); ptr += 4; uint32_t numTriangles = *reinterpret_cast(ptr); ptr += 4; const size_t expectedSize = 16 + static_cast(numVertices) * 8 * sizeof(float) + static_cast(numTriangles) * 3 * sizeof(uint32_t); if (fileData.size() < expectedSize) throw std::runtime_error("Binary mesh file is truncated: " + fileName); std::vector positions(numVertices); std::vector normals(numVertices); std::vector uvs(numVertices); for (uint32_t i = 0; i < numVertices; ++i) { positions[i](0) = *reinterpret_cast(ptr); ptr += 4; positions[i](1) = *reinterpret_cast(ptr); ptr += 4; positions[i](2) = *reinterpret_cast(ptr); ptr += 4; normals[i](0) = *reinterpret_cast(ptr); ptr += 4; normals[i](1) = *reinterpret_cast(ptr); ptr += 4; normals[i](2) = *reinterpret_cast(ptr); ptr += 4; uvs[i](0) = *reinterpret_cast(ptr); ptr += 4; uvs[i](1) = *reinterpret_cast(ptr); ptr += 4; } VertexDataStruct result; result.PositionData.reserve(numTriangles * 3); result.NormalData.reserve(numTriangles * 3); result.TexCoordData.reserve(numTriangles * 3); for (uint32_t i = 0; i < numTriangles; ++i) { for (int k = 0; k < 3; ++k) { uint32_t idx = *reinterpret_cast(ptr); ptr += 4; if (idx >= numVertices) throw std::runtime_error("Triangle index out of range in: " + fileName); result.PositionData.push_back(positions[idx]); result.NormalData.push_back(normals[idx]); result.TexCoordData.push_back(uvs[idx]); } } std::cout << "Binary model loaded: " << numVertices << " verts, " << numTriangles << " tris." << std::endl; s_meshCache[key] = result; return result; } }