From e94e26ae1eb0dd8a3838e66db3abe4006d377ab2 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Fri, 31 Aug 2012 20:55:16 +0200 Subject: New model file format - added new binary and text formats for models - fixes and improvements in CModelFile - tool for converting model files - minor additions and fixes --- src/tools/CMakeLists.txt | 13 ++ src/tools/README.txt | 4 + src/tools/convert_model.cpp | 285 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 302 insertions(+) create mode 100644 src/tools/CMakeLists.txt create mode 100644 src/tools/README.txt create mode 100644 src/tools/convert_model.cpp (limited to 'src/tools') diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt new file mode 100644 index 0000000..f6c6112 --- /dev/null +++ b/src/tools/CMakeLists.txt @@ -0,0 +1,13 @@ +set(CONVERT_MODEL_SOURCES +../common/iman.cpp +../common/logger.cpp +../common/stringutils.cpp +../graphics/engine/modelfile.cpp +convert_model.cpp +) + +include_directories(. ..) + +add_definitions(-DMODELFILE_NO_ENGINE) + +add_executable(convert_model ${CONVERT_MODEL_SOURCES}) diff --git a/src/tools/README.txt b/src/tools/README.txt new file mode 100644 index 0000000..de2f087 --- /dev/null +++ b/src/tools/README.txt @@ -0,0 +1,4 @@ +/** + * \dir tools + * \brief Various tools (separate programs) + */ diff --git a/src/tools/convert_model.cpp b/src/tools/convert_model.cpp new file mode 100644 index 0000000..472f1c6 --- /dev/null +++ b/src/tools/convert_model.cpp @@ -0,0 +1,285 @@ +#include "common/iman.h" +#include "common/logger.h" +#include "graphics/engine/modelfile.h" + +#include +#include + + +bool EndsWith(std::string const &fullString, std::string const &ending) +{ + if (fullString.length() >= ending.length()) { + return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); + } else { + return false; + } +} + + +struct Args +{ + bool usage; + bool dumpInfo; + bool mirror; + std::string inputFile; + std::string outputFile; + std::string inputFormat; + std::string outputFormat; + + Args() + { + usage = false; + dumpInfo = false; + mirror = false; + } +}; + +Args ARGS; + +void PrintUsage(const std::string& program) +{ + std::cerr << "Colobot model converter" << std::endl; + std::cerr << std::endl; + std::cerr << "Usage:" << std::endl; + std::cerr << std::endl; + std::cerr << " Convert files:" << std::endl; + std::cerr << " " << program << " -i input_file -if input_format -o output_file -of output_format [-m]" << std::endl; + std::cerr << " -m => mirror" << std::endl; + std::cerr << std::endl; + std::cerr << " Dump info:" << std::endl; + std::cerr << " " << program << " -d -i input_file -if input_format" << std::endl; + std::cerr << std::endl; + std::cerr << " Help:" << std::endl; + std::cerr << " " << program << " -h" << std::endl; + std::cerr << std::endl; + + std::cerr << "Model formats:" << std::endl; + std::cerr << " old => old binary format" << std::endl; + std::cerr << " new_bin => new binary format" << std::endl; + std::cerr << " new_txt => new text format" << std::endl; +} + +bool ParseArgs(int argc, char *argv[]) +{ + bool waitI = false, waitO = false; + bool waitIf = false, waitOf = false; + for (int i = 1; i < argc; ++i) + { + std::string arg = std::string(argv[i]); + + if (arg == "-i") + { + waitI = true; + continue; + } + if (arg == "-o") + { + waitO = true; + continue; + } + if (arg == "-if") + { + waitIf = true; + continue; + } + if (arg == "-of") + { + waitOf = true; + continue; + } + + if (waitI) + { + waitI = false; + ARGS.inputFile = arg; + } + else if (waitO) + { + waitO = false; + ARGS.outputFile = arg; + } + else if (waitIf) + { + waitIf = false; + ARGS.inputFormat = arg; + } + else if (waitOf) + { + waitOf = false; + ARGS.outputFormat = arg; + } + else if (arg == "-h") + { + PrintUsage(argv[0]); + ARGS.usage = true; + } + else if (arg == "-d") + { + ARGS.dumpInfo = true; + } + else if (arg == "-m") + { + ARGS.mirror = true; + } + else + { + return false; + } + } + + if (waitI || waitO || waitIf || waitOf) + return false; + + if (ARGS.usage) + return true; + + if (ARGS.inputFile.empty() || (!ARGS.dumpInfo && ARGS.outputFile.empty() )) + return false; + + if (ARGS.inputFormat.empty() || (!ARGS.dumpInfo && ARGS.outputFormat.empty() )) + return false; + + return true; +} + +template +void PrintStats(const std::map& stats, int total) +{ + for (auto it = stats.begin(); it != stats.end(); ++it) + { + std::cerr << " " << (*it).first << " : " << (*it).second << " / " << total << std::endl; + } +} + +int main(int argc, char *argv[]) +{ + CLogger logger; + + if (!ParseArgs(argc, argv)) + { + std::cerr << "Invalid arguments! Run with -h for usage info." << std::endl; + return 1; + } + + if (ARGS.usage) + return 0; + + CInstanceManager iMan; + Gfx::CModelFile model(&iMan); + + bool ok = true; + + if (ARGS.inputFormat == "old") + { + ok = model.ReadModel(ARGS.inputFile); + } + else if (ARGS.inputFormat == "new_bin") + { + ok = model.ReadBinaryModel(ARGS.inputFile); + } + else if (ARGS.inputFormat == "new_txt") + { + ok = model.ReadTextModel(ARGS.inputFile); + } + else + { + std::cerr << "Invalid input format" << std::endl; + return 1; + } + + if (!ok) + { + std::cerr << "Reading input model failed" << std::endl; + return 1; + } + + if (ARGS.dumpInfo) + { + const std::vector& triangles = model.GetTriangles(); + + Math::Vector min( Math::HUGE_NUM, Math::HUGE_NUM, Math::HUGE_NUM); + Math::Vector max(-Math::HUGE_NUM, -Math::HUGE_NUM, -Math::HUGE_NUM); + + std::map texs1, texs2; + std::map states; + std::map mins, maxs; + int variableTexs2 = 0; + + for (int i = 0; i < static_cast( triangles.size() ); ++i) + { + const Gfx::ModelTriangle& t = triangles[i]; + + min.x = Math::Min(t.p1.coord.x, t.p2.coord.x, t.p3.coord.x, min.x); + min.y = Math::Min(t.p1.coord.y, t.p2.coord.y, t.p3.coord.y, min.y); + min.z = Math::Min(t.p1.coord.z, t.p2.coord.z, t.p3.coord.z, min.z); + + max.x = Math::Max(t.p1.coord.x, t.p2.coord.x, t.p3.coord.x, max.x); + max.y = Math::Max(t.p1.coord.y, t.p2.coord.y, t.p3.coord.y, max.y); + max.z = Math::Max(t.p1.coord.z, t.p2.coord.z, t.p3.coord.z, max.z); + + texs1[t.tex1Name] += 1; + if (! t.tex2Name.empty()) + texs2[t.tex2Name] += 1; + if (t.variableTex2) + variableTexs2 += 1; + states[t.state] += 1; + + mins[t.min] += 1; + maxs[t.max] += 1; + } + + std::cerr << "---- Info ----" << std::endl; + std::cerr << "Total triangles: " << triangles.size(); + std::cerr << std::endl; + std::cerr << "Bounding box:" << std::endl; + std::cerr << " min: [" << min.x << ", " << min.y << ", " << min.z << "]" << std::endl; + std::cerr << " max: [" << max.x << ", " << max.y << ", " << max.z << "]" << std::endl; + std::cerr << std::endl; + std::cerr << "Textures:" << std::endl; + std::cerr << " tex1:" << std::endl; + PrintStats(texs1, triangles.size()); + std::cerr << " tex2:" << std::endl; + PrintStats(texs2, triangles.size()); + std::cerr << " variable tex2: " << variableTexs2 << " / " << triangles.size() << std::endl; + std::cerr << std::endl; + std::cerr << "States:" << std::endl; + PrintStats(states, triangles.size()); + std::cerr << std::endl; + std::cerr << "LOD:" << std::endl; + std::cerr << " min:" << std::endl; + PrintStats(mins, triangles.size()); + std::cerr << " max:" << std::endl; + PrintStats(maxs, triangles.size()); + + return 0; + } + + if (ARGS.mirror) + model.Mirror(); + + if (ARGS.outputFormat == "old") + { + ok = model.WriteModel(ARGS.outputFile); + } + else if (ARGS.outputFormat == "new_bin") + { + ok = model.WriteBinaryModel(ARGS.outputFile); + } + else if (ARGS.outputFormat == "new_txt") + { + ok = model.WriteTextModel(ARGS.outputFile); + } + else + { + std::cerr << "Invalid output format" << std::endl; + return 1; + } + + if (!ok) + { + std::cerr << "Writing output model failed" << std::endl; + return 1; + } + + return 0; +} -- cgit v1.2.3-1-g7c22