#include "CShapeCompiler.h" #include "CBinaryFile.h" #include "CScopeExit.h" #include "U_Log.h" #include "U_String.h" #include "U_Files.h" #include #include #include "glm/glm.hpp" bool CShapeCompiler::CompileShape(const std::filesystem::path& srcpath) { std::ifstream objfile(srcpath); if (!objfile.is_open()) { Log::ErrInstance() << "Can't open source file\n"; return false; } CScopeExit streamExiter([&objfile]() { objfile.close(); }); std::filesystem::path outpath = FileUtils::get_executable_path() / "resources" / "shapes" / (srcpath.stem().string() + ".eshp"); CBinaryFile outfile(outpath, false); //closed on destructor if(!outfile.IsOpen()) { Log::ErrInstance() << "Can't open output file\n"; return false; } glm::vec3 Scale{ 1.0f, 1.0f, 1.0f }; int CurrentMaterial = -1; std::vector Vertices; struct Triangle { int MaterialID = -1; glm::uvec3 Indices; }; std::vector Triangles; std::vector MaterialsList; std::string ReadLine; while (!objfile.eof()) { std::getline(objfile, ReadLine, '\n'); if (ReadLine.substr(0, 5) == "scale") { std::vector splitted; StringUtils::split_str(ReadLine, ' ', splitted); float scl = atof(splitted[1].c_str()); Scale = { scl, scl, scl }; Log::Instance() << "Scaled to " << scl << "\n"; } else if (ReadLine.substr(0, 6) == "scale3") { std::vector splitted; StringUtils::split_str(ReadLine, ' ', splitted); float scl[3]; for(int i = 0; i < 3; i++) { scl[i] = atof(splitted[i + 1].c_str()); } Scale = { scl[0], scl[1], scl[2] }; Log::Instance() << "Scaled to { " << StringUtils::ToStr(Scale) << " }\n"; } else if (ReadLine[0] == 'v' && (ReadLine[1] == ' ' || ReadLine[1] == '\t')) { float X, Y, Z; sscanf(ReadLine.c_str(), "v %f %f %f", &X, &Y, &Z); X *= Scale.x; Y *= Scale.y; Z *= Scale.z; Vertices.push_back({ X, Y, Z }); } else if (ReadLine[0] == 'l') { ReadLine.erase(0, 2); bool found = std::find(MaterialsList.begin(), MaterialsList.end(), ReadLine) != MaterialsList.end(); if (!found) { MaterialsList.push_back(ReadLine); Log::Instance() << "Added material " << ReadLine << "\n"; } CurrentMaterial = std::distance(MaterialsList.begin(), std::find(MaterialsList.begin(), MaterialsList.end(), ReadLine)); } else if (ReadLine[0] == 'm') { ReadLine.erase(0, 2); bool found = std::find(MaterialsList.begin(), MaterialsList.end(), ReadLine) != MaterialsList.end(); if (!found) { MaterialsList.push_back(ReadLine); Log::Instance() << "Forced material " << ReadLine << "\n"; } CurrentMaterial = std::distance(MaterialsList.begin(), std::find(MaterialsList.begin(), MaterialsList.end(), ReadLine)); } else if (ReadLine[0] == 'f') { int vertex[3]; int texture[3]; int normal[3]; sscanf(ReadLine.c_str(), "f %d/%d/%d %d/%d/%d %d/%d/%d", &vertex[0], &texture[0], &normal[0], &vertex[1], &texture[1], &normal[1], &vertex[2], &texture[2], &normal[2]); Triangle triangle; for(int i = 0; i < 3; i++) { triangle.Indices[i] = vertex[i] - 1; } //converted to base-0 triangle.MaterialID = CurrentMaterial; Triangles.push_back(triangle); } } outfile.Write(0); //placeholder (file size) outfile.Write(Vertices.size()); outfile.Write(MaterialsList.size()); Log::Instance() << "Vertices size is " << Vertices.size() << Log::Endl; Log::Instance() << "MaterialsList size is " << MaterialsList.size() << Log::Endl; for(std::uint64_t i = 0; i < Vertices.size(); i++) { outfile.Write(Vertices[i]); } for(std::uint64_t i = 0; i < MaterialsList.size(); i++) { size_t seek = outfile.GetSeek(); outfile.Write(0); //placeholder (tris count) outfile.WriteLenString(MaterialsList.at(i)); std::uint64_t count = 0; for(std::uint64_t j = 0; j < Triangles.size(); j++) { auto& tri = Triangles.at(j); if(tri.MaterialID == i) { outfile.Write ( { static_cast(tri.Indices.x), static_cast(tri.Indices.y), static_cast(tri.Indices.z) } ); count++; } } size_t curseek = outfile.GetSeek(); outfile.SetSeek(seek); outfile.Write(count); //written placeholder for tris count outfile.SetSeek(curseek); } size_t seek = outfile.GetSeek(); outfile.SetSeek(0); size_t fileSize = seek - sizeof(std::uint64_t); Log::Instance() << "File size is " << fileSize << Log::Endl; outfile.Write(fileSize); outfile.Close(); Log::Instance() << "Collision shape compiled!\n"; return true; }