123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- /*
- ---------------------------------------------------------------------------
- Open Asset Import Library (assimp)
- ---------------------------------------------------------------------------
- Copyright (c) 2006-2024, assimp team
- All rights reserved.
- Redistribution and use of this software in source and binary forms,
- with or without modification, are permitted provided that the following
- conditions are met:
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
- * Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ---------------------------------------------------------------------------
- */
- /** @file Info.cpp
- * @brief Implementation of the 'assimp info' utility */
- #include "Main.h"
- #include <cstdio>
- #include <iostream>
- #include <string>
- constexpr char AICMD_MSG_INFO_HELP_E[] =
- "assimp info <file> [-r] [-v]\n"
- "\tPrint basic structure of a 3D model\n"
- "\t-r,--raw: No postprocessing, do a raw import\n"
- "\t-v,--verbose: Print verbose info such as node transform data\n"
- "\t-s, --silent: Print only minimal info\n";
- // note: by default this is using utf-8 text.
- // this is well supported on pretty much any linux terminal.
- // if this causes problems on some platform,
- // put an #ifdef to use the ascii version for that platform.
- #ifdef _WIN32
- constexpr char TREE_BRANCH_ASCII[] = "|-";
- constexpr char TREE_STOP_ASCII[] = "'-";
- constexpr char TREE_CONTINUE_ASCII[] = "| ";
- const char *TREE_BRANCH = TREE_BRANCH_ASCII;
- const char *TREE_STOP = TREE_STOP_ASCII;
- const char *TREE_CONTINUE = TREE_CONTINUE_ASCII;
- #else // _WIN32
- constexpr char TREE_BRANCH_UTF8[] = "\xe2\x94\x9c\xe2\x95\xb4";
- constexpr char TREE_STOP_UTF8[] = "\xe2\x94\x94\xe2\x95\xb4";
- constexpr char TREE_CONTINUE_UTF8[] = "\xe2\x94\x82 ";
- const char *TREE_BRANCH = TREE_BRANCH_UTF8;
- const char *TREE_STOP = TREE_STOP_UTF8;
- const char *TREE_CONTINUE = TREE_CONTINUE_UTF8;
- #endif // _WIN32
- // -----------------------------------------------------------------------------------
- unsigned int CountNodes(const aiNode *root) {
- unsigned int i = 0;
- for (unsigned int a = 0; a < root->mNumChildren; ++a) {
- i += CountNodes(root->mChildren[a]);
- }
- return 1 + i;
- }
- // -----------------------------------------------------------------------------------
- unsigned int GetMaxDepth(const aiNode *root) {
- unsigned int cnt = 0;
- for (unsigned int i = 0; i < root->mNumChildren; ++i) {
- cnt = std::max(cnt, GetMaxDepth(root->mChildren[i]));
- }
- return cnt + 1;
- }
- // -----------------------------------------------------------------------------------
- unsigned int CountVertices(const aiScene *scene) {
- unsigned int cnt = 0;
- for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
- cnt += scene->mMeshes[i]->mNumVertices;
- }
- return cnt;
- }
- // -----------------------------------------------------------------------------------
- unsigned int CountFaces(const aiScene *scene) {
- unsigned int cnt = 0;
- for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
- cnt += scene->mMeshes[i]->mNumFaces;
- }
- return cnt;
- }
- // -----------------------------------------------------------------------------------
- unsigned int CountBones(const aiScene *scene) {
- unsigned int cnt = 0;
- for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
- cnt += scene->mMeshes[i]->mNumBones;
- }
- return cnt;
- }
- // -----------------------------------------------------------------------------------
- unsigned int CountAnimChannels(const aiScene *scene) {
- unsigned int cnt = 0;
- for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
- cnt += scene->mAnimations[i]->mNumChannels;
- }
- return cnt;
- }
- // -----------------------------------------------------------------------------------
- unsigned int GetAvgFacePerMesh(const aiScene *scene) {
- return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountFaces(scene) / scene->mNumMeshes) : 0;
- }
- // -----------------------------------------------------------------------------------
- unsigned int GetAvgVertsPerMesh(const aiScene *scene) {
- return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountVertices(scene) / scene->mNumMeshes) : 0;
- }
- // -----------------------------------------------------------------------------------
- void FindSpecialPoints(const aiScene *scene, const aiNode *root, aiVector3D special_points[3], const aiMatrix4x4 &mat = aiMatrix4x4()) {
- // XXX that could be greatly simplified by using code from code/ProcessHelper.h
- // XXX I just don't want to include it here.
- const aiMatrix4x4 trafo = root->mTransformation * mat;
- for (unsigned int i = 0; i < root->mNumMeshes; ++i) {
- const aiMesh *mesh = scene->mMeshes[root->mMeshes[i]];
- for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
- aiVector3D v = trafo * mesh->mVertices[a];
- special_points[0].x = std::min(special_points[0].x, v.x);
- special_points[0].y = std::min(special_points[0].y, v.y);
- special_points[0].z = std::min(special_points[0].z, v.z);
- special_points[1].x = std::max(special_points[1].x, v.x);
- special_points[1].y = std::max(special_points[1].y, v.y);
- special_points[1].z = std::max(special_points[1].z, v.z);
- }
- }
- for (unsigned int i = 0; i < root->mNumChildren; ++i) {
- FindSpecialPoints(scene, root->mChildren[i], special_points, trafo);
- }
- }
- // -----------------------------------------------------------------------------------
- void FindSpecialPoints(const aiScene *scene, aiVector3D special_points[3]) {
- special_points[0] = aiVector3D(1e10, 1e10, 1e10);
- special_points[1] = aiVector3D(-1e10, -1e10, -1e10);
- FindSpecialPoints(scene, scene->mRootNode, special_points);
- special_points[2] = (special_points[0] + special_points[1]) * (ai_real)0.5;
- }
- // -----------------------------------------------------------------------------------
- std::string FindPTypes(const aiScene *scene) {
- bool haveit[4] = { false };
- for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
- const unsigned int pt = scene->mMeshes[i]->mPrimitiveTypes;
- if (pt & aiPrimitiveType_POINT) {
- haveit[0] = true;
- }
- if (pt & aiPrimitiveType_LINE) {
- haveit[1] = true;
- }
- if (pt & aiPrimitiveType_TRIANGLE) {
- haveit[2] = true;
- }
- if (pt & aiPrimitiveType_POLYGON) {
- haveit[3] = true;
- }
- }
- return (haveit[0] ? std::string("points") : "") + (haveit[1] ? "lines" : "") +
- (haveit[2] ? "triangles" : "") + (haveit[3] ? "n-polygons" : "");
- }
- // -----------------------------------------------------------------------------------
- // Prettily print the node graph to stdout
- void PrintHierarchy(
- const aiNode *node,
- const std::string &indent,
- bool verbose,
- bool last = false,
- bool first = true) {
- // tree visualization
- std::string branchchar;
- if (first) {
- branchchar = "";
- } else if (last) {
- branchchar = TREE_STOP;
- } // "'-"
- else {
- branchchar = TREE_BRANCH;
- } // "|-"
- // print the indent and the branch character and the name
- std::cout << indent << branchchar << node->mName.C_Str();
- // if there are meshes attached, indicate this
- if (node->mNumMeshes) {
- std::cout << " (mesh ";
- bool sep = false;
- for (size_t i = 0; i < node->mNumMeshes; ++i) {
- unsigned int mesh_index = node->mMeshes[i];
- if (sep) {
- std::cout << ", ";
- }
- std::cout << mesh_index;
- sep = true;
- }
- std::cout << ")";
- }
- // finish the line
- std::cout << std::endl;
- // in verbose mode, print the transform data as well
- if (verbose) {
- // indent to use
- std::string indentadd;
- if (last) {
- indentadd += " ";
- } else {
- indentadd += TREE_CONTINUE;
- } // "| "..
- if (node->mNumChildren == 0) {
- indentadd += " ";
- } else {
- indentadd += TREE_CONTINUE;
- } // .."| "
- aiVector3D s, r, t;
- node->mTransformation.Decompose(s, r, t);
- if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
- std::cout << indent << indentadd;
- printf(" S:[%f %f %f]\n", s.x, s.y, s.z);
- }
- if (r.x || r.y || r.z) {
- std::cout << indent << indentadd;
- printf(" R:[%f %f %f]\n", r.x, r.y, r.z);
- }
- if (t.x || t.y || t.z) {
- std::cout << indent << indentadd;
- printf(" T:[%f %f %f]\n", t.x, t.y, t.z);
- }
- }
- // and recurse
- std::string nextIndent;
- if (first) {
- nextIndent = indent;
- } else if (last) {
- nextIndent = indent + " ";
- } else {
- nextIndent = indent + TREE_CONTINUE;
- } // "| "
- for (size_t i = 0; i < node->mNumChildren; ++i) {
- bool lastone = (i == node->mNumChildren - 1);
- PrintHierarchy(
- node->mChildren[i],
- nextIndent,
- verbose,
- lastone,
- false);
- }
- }
- // -----------------------------------------------------------------------------------
- // Implementation of the assimp info utility to print basic file info
- int Assimp_Info(const char *const *params, unsigned int num) {
- // asssimp info <file> [-r]
- if (num < 1) {
- printf("assimp info: Invalid number of arguments. "
- "See \'assimp info --help\'\n");
- return AssimpCmdError::InvalidNumberOfArguments;
- }
- // --help
- if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) {
- printf("%s", AICMD_MSG_INFO_HELP_E);
- return AssimpCmdError::Success;
- }
- const std::string in = std::string(params[0]);
- // get -r and -v arguments
- bool raw = false;
- bool verbose = false;
- bool silent = false;
- for (unsigned int i = 1; i < num; ++i) {
- if (!strcmp(params[i], "--raw") || !strcmp(params[i], "-r")) {
- raw = true;
- }
- if (!strcmp(params[i], "--verbose") || !strcmp(params[i], "-v")) {
- verbose = true;
- }
- if (!strcmp(params[i], "--silent") || !strcmp(params[i], "-s")) {
- silent = true;
- }
- }
- // Verbose and silent at the same time are not allowed
- if (verbose && silent) {
- printf("assimp info: Invalid arguments, verbose and silent at the same time are forbidden. ");
- return AssimpCmdInfoError::InvalidCombinaisonOfArguments;
- }
- // Parse post-processing flags unless -r was specified
- ImportData import;
- if (!raw) {
- // get import flags
- ProcessStandardArguments(import, params + 1, num - 1);
- //No custom post process flags defined, we set all the post process flags active
- if (import.ppFlags == 0)
- import.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality;
- }
- // import the main model
- const aiScene *scene = ImportModel(import, in);
- if (!scene) {
- printf("assimp info: Unable to load input file %s\n",
- in.c_str());
- return AssimpCmdError::FailedToLoadInputFile;
- }
- aiMemoryInfo mem;
- globalImporter->GetMemoryRequirements(mem);
- static const char *format_string =
- "Memory consumption: %i B\n"
- "Nodes: %i\n"
- "Maximum depth %i\n"
- "Meshes: %i\n"
- "Animations: %i\n"
- "Textures (embed.): %i\n"
- "Materials: %i\n"
- "Cameras: %i\n"
- "Lights: %i\n"
- "Vertices: %i\n"
- "Faces: %i\n"
- "Bones: %i\n"
- "Animation Channels: %i\n"
- "Primitive Types: %s\n"
- "Average faces/mesh %i\n"
- "Average verts/mesh %i\n"
- "Minimum point (%f %f %f)\n"
- "Maximum point (%f %f %f)\n"
- "Center point (%f %f %f)\n"
- ;
- aiVector3D special_points[3];
- FindSpecialPoints(scene, special_points);
- printf(format_string,
- mem.total,
- CountNodes(scene->mRootNode),
- GetMaxDepth(scene->mRootNode),
- scene->mNumMeshes,
- scene->mNumAnimations,
- scene->mNumTextures,
- scene->mNumMaterials,
- scene->mNumCameras,
- scene->mNumLights,
- CountVertices(scene),
- CountFaces(scene),
- CountBones(scene),
- CountAnimChannels(scene),
- FindPTypes(scene).c_str(),
- GetAvgFacePerMesh(scene),
- GetAvgVertsPerMesh(scene),
- special_points[0][0], special_points[0][1], special_points[0][2],
- special_points[1][0], special_points[1][1], special_points[1][2],
- special_points[2][0], special_points[2][1], special_points[2][2]);
- if (silent) {
- printf("\n");
- return AssimpCmdError::Success;
- }
- // meshes
- if (scene->mNumMeshes) {
- printf("\nMeshes: (name) [vertices / bones / faces | primitive_types]\n");
- }
- for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
- const aiMesh *mesh = scene->mMeshes[i];
- printf(" %d (%s)", i, mesh->mName.C_Str());
- printf(
- ": [%d / %d / %d |",
- mesh->mNumVertices,
- mesh->mNumBones,
- mesh->mNumFaces);
- const unsigned int ptypes = mesh->mPrimitiveTypes;
- if (ptypes & aiPrimitiveType_POINT) {
- printf(" point");
- }
- if (ptypes & aiPrimitiveType_LINE) {
- printf(" line");
- }
- if (ptypes & aiPrimitiveType_TRIANGLE) {
- printf(" triangle");
- }
- if (ptypes & aiPrimitiveType_POLYGON) {
- printf(" polygon");
- }
- printf("]\n");
- }
- // materials
- if (scene->mNumMaterials)
- printf("\nNamed Materials:");
- for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
- const aiMaterial *mat = scene->mMaterials[i];
- aiString name = mat->GetName();
- printf("\n \'%s\'", name.data);
- if (mat->mNumProperties)
- printf(" (prop) [index / bytes | texture semantic]");
- for (unsigned p = 0; p < mat->mNumProperties; p++) {
- const aiMaterialProperty *prop = mat->mProperties[p];
- const aiTextureType textype = static_cast<aiTextureType>(prop->mSemantic);
- printf("\n %d (%s): [%d / %d | %s]",
- p,
- prop->mKey.data,
- prop->mIndex,
- prop->mDataLength,
- aiTextureTypeToString(textype));
- }
- }
- if (scene->mNumMaterials) {
- printf("\n");
- }
- // textures
- unsigned int total = 0;
- for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
- aiString name;
- static const aiTextureType types[] = {
- aiTextureType_NONE,
- aiTextureType_DIFFUSE,
- aiTextureType_SPECULAR,
- aiTextureType_AMBIENT,
- aiTextureType_EMISSIVE,
- aiTextureType_HEIGHT,
- aiTextureType_NORMALS,
- aiTextureType_SHININESS,
- aiTextureType_OPACITY,
- aiTextureType_DISPLACEMENT,
- aiTextureType_LIGHTMAP,
- aiTextureType_REFLECTION,
- aiTextureType_BASE_COLOR,
- aiTextureType_NORMAL_CAMERA,
- aiTextureType_EMISSION_COLOR,
- aiTextureType_METALNESS,
- aiTextureType_DIFFUSE_ROUGHNESS,
- aiTextureType_AMBIENT_OCCLUSION,
- aiTextureType_UNKNOWN
- };
- for (unsigned int type = 0; type < sizeof(types) / sizeof(types[0]); ++type) {
- for (unsigned int idx = 0; AI_SUCCESS == aiGetMaterialString(scene->mMaterials[i],
- AI_MATKEY_TEXTURE(types[type], idx), &name);
- ++idx) {
- printf("%s\n \'%s\'", (total++ ? "" : "\nTexture Refs:"), name.data);
- }
- }
- }
- if (total) {
- printf("\n");
- }
- // animations
- total = 0;
- for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
- if (scene->mAnimations[i]->mName.length) {
- printf("%s\n \'%s\'", (total++ ? "" : "\nNamed Animations:"), scene->mAnimations[i]->mName.data);
- }
- }
- if (total) {
- printf("\n");
- }
- // node hierarchy
- printf("\nNode hierarchy:\n");
- PrintHierarchy(scene->mRootNode, "", verbose);
- printf("\n");
- return AssimpCmdError::Success;
- }
|