|
| 1 | +#include <argparse/argparse.hpp> |
| 2 | +#include <cstdio> |
| 3 | +#include <iostream> |
| 4 | +#include <string> |
| 5 | +#include <string.h> |
| 6 | +#include <vector> |
| 7 | + |
| 8 | +#include "main.h" |
| 9 | + |
| 10 | +#include <libInfinite/logger/ConsoleLogger.h> |
| 11 | +#include <libInfinite/tags/TagManager.h> |
| 12 | + |
| 13 | +#include <glm/gtc/quaternion.hpp> |
| 14 | +#include <glm/gtx/euler_angles.hpp> |
| 15 | +#include <glm/gtx/transform.hpp> |
| 16 | + |
| 17 | +#include <3D/AssImpExporter.h> |
| 18 | + |
| 19 | + |
| 20 | +#ifdef _WIN64 |
| 21 | +#include <windows.h> |
| 22 | +#include <fileapi.h> |
| 23 | +//#include <direct.h> |
| 24 | + |
| 25 | +//#warning WIN64 detected |
| 26 | +#endif |
| 27 | + |
| 28 | +#include <dirent.h> |
| 29 | +#include <sys/types.h> |
| 30 | +#include <sys/stat.h> |
| 31 | +#include <fcntl.h> |
| 32 | + |
| 33 | +int main(int argc, char* argv[]){ |
| 34 | + argparse::ArgumentParser parser("infinteExplorerCLI"); |
| 35 | + |
| 36 | + parser.add_argument("-d","--deploy").help("Path which is searched for module files") |
| 37 | + .default_value<std::vector<std::string>>({}).append(); |
| 38 | + int verbosity = 0; |
| 39 | + parser.add_argument("-V", "--verbose").help("increase logging verbosity").action([&](const auto &) {++verbosity;}). |
| 40 | + append().default_value(false).implicit_value(true).nargs(0); |
| 41 | + |
| 42 | + parser.add_argument("-i", "--globalid").help("global ID of the main tag to load. This is an unsigned 32bit number").scan<'i',uint32_t>(); |
| 43 | + |
| 44 | + parser.add_argument("-e", "--export").help("Export data from the tag. Currently only SBSP").default_value(false).implicit_value(true); |
| 45 | + |
| 46 | + parser.add_argument("-o", "--output").help("Output path").default_value("--"); |
| 47 | + |
| 48 | + try{ |
| 49 | + parser.parse_args(argc, argv); |
| 50 | + } catch(const std::runtime_error& err){ |
| 51 | + std::cerr << err.what() << std::endl; |
| 52 | + std::cerr << parser; |
| 53 | + return -1; |
| 54 | + } |
| 55 | + |
| 56 | + FILE* loggerfile; |
| 57 | + |
| 58 | + if(parser.get<std::string>("-o") == "--"){ |
| 59 | + loggerfile = stderr; |
| 60 | + } else { |
| 61 | + loggerfile = stdout; |
| 62 | + } |
| 63 | + |
| 64 | + int generalLogLevel = std::max(LOG_LEVEL_ERROR - verbosity,0); |
| 65 | + ConsoleLogger generalLogger(generalLogLevel, "", loggerfile); |
| 66 | + |
| 67 | + int libInfLogLevel = std::max(LOG_LEVEL_ERROR - verbosity,0); |
| 68 | + ConsoleLogger libInfLogger(libInfLogLevel,"[libInfinite] ", loggerfile); |
| 69 | + ModuleManager modman(&libInfLogger); |
| 70 | + TagManager tagman(&modman,&libInfLogger); |
| 71 | + |
| 72 | + for(auto path : parser.get<std::vector<std::string>>("-d")){ |
| 73 | + loadPathRecursive(path, &libInfLogger, modman); |
| 74 | + } |
| 75 | + |
| 76 | + if(modman.modules.size() == 0){ |
| 77 | + generalLogger.log(LOG_LEVEL_CRITICAL, "No modules loaded! Aborting\n"); |
| 78 | + return -1; |
| 79 | + } |
| 80 | + generalLogger.log(LOG_LEVEL_INFO,"Loaded %d modules\n",modman.modules.size()); |
| 81 | + modman.buildNodeTree(); |
| 82 | + |
| 83 | + uint32_t globalId = 0; |
| 84 | + bool globalIdSet = false; |
| 85 | + if(auto id = parser.present<uint32_t>("--globalid")){ |
| 86 | + globalId = *id; |
| 87 | + globalIdSet = true; |
| 88 | + } |
| 89 | + |
| 90 | + // check if this global ID exists, and get the associated item |
| 91 | + if(modman.assetIdItems.contains(globalId) && globalIdSet){ |
| 92 | + if(parser.get<bool>("-e")){ |
| 93 | + Tag* tag = tagman.getTag(globalId); |
| 94 | + if(modman.assetIdItems[globalId]->tagType == 'sbsp'){ |
| 95 | + if(exportBSP(dynamic_cast<sbspHandle*>(tag), parser.get<std::string>("-o"), &generalLogger)){ |
| 96 | + return -1; |
| 97 | + } |
| 98 | + } |
| 99 | + } |
| 100 | + } else if(globalIdSet) { |
| 101 | + generalLogger.log(LOG_LEVEL_CRITICAL, "That global ID doesn't exist!\n"); |
| 102 | + return -1; |
| 103 | + } |
| 104 | + |
| 105 | +} |
| 106 | + |
| 107 | +int exportBSP(sbspHandle* handle, std::string out, Logger* logger){ |
| 108 | + if(handle == nullptr){ |
| 109 | + logger->log(LOG_LEVEL_CRITICAL, "No BSP tag handle to export!\n"); |
| 110 | + return -1; |
| 111 | + } |
| 112 | + AssImpExporter exporter; |
| 113 | + exporter.setLogger(logger); |
| 114 | + exporter.newScene(); |
| 115 | + |
| 116 | + int c = handle->getGeoInstanceCount(); |
| 117 | + int f = 0; |
| 118 | + int i; |
| 119 | + for(i = 0; i < c; i++){ |
| 120 | + auto inst = handle->getGeoInstanceInfo(i); |
| 121 | + if(inst.geo == nullptr){ |
| 122 | + // later, maybe add an error here (maybe like source?), but for now, just skip it |
| 123 | + continue; |
| 124 | + } |
| 125 | + if(inst.mesh_flags_override & MESH_FLAGS_OVERRIDE_MESH_IS_CUSTOM_SHADOW_CASTER){ |
| 126 | + // just don't to anything with shadowcasters for now. Other wizards are allowed though. |
| 127 | + continue; |
| 128 | + } |
| 129 | + f++; |
| 130 | + |
| 131 | + auto meshdata = inst.geo->getMeshData(inst.meshIndex); |
| 132 | + |
| 133 | + glm::mat3 meshrot_mat(meshdata.forward, meshdata.left, meshdata.up); |
| 134 | + glm::mat4 meshposmat = glm::translate(meshdata.position); |
| 135 | + glm::mat4 meshscalemat = glm::scale(meshdata.scale); |
| 136 | + glm::mat4 meshtransform = meshposmat * glm::mat4(meshrot_mat) * meshscalemat; |
| 137 | + |
| 138 | + |
| 139 | + glm::mat3 rot_mat(inst.forward, inst.left, inst.up); |
| 140 | + //glm::mat3 rot_mat(glm::vec3(inst.up.x,inst.forward.x,inst.left.x), glm::vec3(inst.up.y,inst.forward.y,inst.left.y), glm::vec3(inst.up.z,inst.forward.z,inst.left.z)); |
| 141 | + //glm::mat3 rot_mat(inst.up, inst.forward, inst.left); |
| 142 | + glm::mat4 bigrotmat(rot_mat); |
| 143 | + //bigrotmat = glm::transpose(bigrotmat); |
| 144 | + glm::vec3 rotation = glm::eulerAngles(glm::quat_cast(rot_mat)); |
| 145 | + rotation = glm::degrees(rotation); |
| 146 | + glm::vec4 rotatedPos = glm::rotate(glm::radians(-90.0f), glm::vec3(1.0,0.0,0.0)) * glm::vec4(inst.position,1.0f); |
| 147 | + //globalWindowPointer->viewer3D.addRenderGeo(&inst.geo->geoHandle, inst.meshIndex, inst.position, bigrotmat, -inst.scale); // glm::vec3(rotatedPos.x,rotatedPos.y,rotatedPos.z) |
| 148 | + exporter.addRenderGeo(&inst.geo->geoHandle, inst.meshIndex, inst.position, rot_mat, inst.scale,"owo"); |
| 149 | + } |
| 150 | + logger->log(LOG_LEVEL_INFO, "%d Instances in total, %d included in export (shadowcasters are excluded)\n", i, f); |
| 151 | + exporter.exportScene(out); |
| 152 | + return 0; |
| 153 | +} |
| 154 | +// duplicate code, since this is currently in ModuleDisplayManager, which is only used in the GUI |
| 155 | + |
| 156 | +void loadPathRecursive(std::string path, Logger* logger, ModuleManager& modMan){ |
| 157 | + |
| 158 | + // this has to be done differently on POSIX-compliant systems and /windows/ ...sigh |
| 159 | + |
| 160 | +#ifdef _WIN64 |
| 161 | + // windows version |
| 162 | + WIN32_FIND_DATA find; |
| 163 | + HANDLE dirHandle; |
| 164 | + |
| 165 | + std::string searchPath = path + "/*"; |
| 166 | + |
| 167 | + dirHandle = FindFirstFile(searchPath.c_str(), &find); |
| 168 | + |
| 169 | + if (dirHandle == INVALID_HANDLE_VALUE) { |
| 170 | + logger->log(LOG_LEVEL_WARNING,"Could not open %s\n", path.c_str()); |
| 171 | + return; |
| 172 | + } |
| 173 | + |
| 174 | + do { |
| 175 | + std::string cPath = path + "\\" + find.cFileName; |
| 176 | + //printf("Found %s\n",cPath.c_str()); |
| 177 | + if (!(strncmp(find.cFileName, ".", 2) && strncmp(find.cFileName, "..", 3))) { |
| 178 | + // . or .., skip those |
| 179 | + continue; |
| 180 | + } |
| 181 | + |
| 182 | + if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |
| 183 | + // is a directory |
| 184 | + //printf("This is a directory\n"); |
| 185 | + loadPathRecursive(cPath, logger, modMan); |
| 186 | + |
| 187 | + // don't do the other stuff, which is only for files |
| 188 | + continue; |
| 189 | + } |
| 190 | + |
| 191 | + // this is only for files |
| 192 | + |
| 193 | + std::string name(find.cFileName); |
| 194 | + |
| 195 | + // all of this can just be copied from the posix version |
| 196 | + if (name.size() < 7) { |
| 197 | + // name is too short |
| 198 | + continue; |
| 199 | + } |
| 200 | + if (name.substr(name.size() - 7, 7) == ".module") { |
| 201 | + // extension should match |
| 202 | + if (modMan.addModule(cPath.c_str())) { |
| 203 | + // the module couldn't be loaded |
| 204 | + logger->log(LOG_LEVEL_ERROR,"Failed to load module %s, skipping!\n", cPath.c_str()); |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + |
| 209 | + } while (FindNextFile(dirHandle,&find)); |
| 210 | +#else |
| 211 | + // the posix version |
| 212 | + DIR* dir; |
| 213 | + dir = opendir(path.c_str()); // open the current directory |
| 214 | + if(!dir){ |
| 215 | + // something went wrong opening the directory |
| 216 | + logger->log(LOG_LEVEL_WARNING,"Failed to open %s\n",path.c_str()); |
| 217 | + return; |
| 218 | + } |
| 219 | + struct dirent* ent; |
| 220 | + ent = readdir(dir); |
| 221 | + struct stat buf; |
| 222 | + while(ent){ |
| 223 | + // for every entry |
| 224 | + std::string cPath = path + "/" + ent->d_name; |
| 225 | + if(stat(cPath.c_str(),&buf)){ |
| 226 | + // something went wrong with stat |
| 227 | + // report the error and just skip this entry |
| 228 | + logger->log(LOG_LEVEL_WARNING,"Failed to stat %s!\n",cPath.c_str()); // warning because it might not be an actual issue |
| 229 | + goto next; // skip to the next entry |
| 230 | + continue; |
| 231 | + } |
| 232 | + if(S_ISDIR(buf.st_mode)){ |
| 233 | + // another directory, check that one too |
| 234 | + if(strncmp(ent->d_name,".",2) && strncmp(ent->d_name,"..",3)){ |
| 235 | + //printf("Looking in %s\n",cPath.c_str()); |
| 236 | + loadPathRecursive(cPath, logger, modMan); |
| 237 | + } |
| 238 | + |
| 239 | + } |
| 240 | + if(S_ISREG(buf.st_mode)){ |
| 241 | + // regular file, but that doesn't mean it's a module |
| 242 | + // first check the file extension (.module, the last 7 characters of the name) |
| 243 | + std::string name(ent->d_name); |
| 244 | + if(name.size() < 7){ |
| 245 | + // name is too short |
| 246 | + goto next; |
| 247 | + } |
| 248 | + if(name.substr(name.size() - 7, 7) == ".module"){ |
| 249 | + // extension should match |
| 250 | + if(modMan.addModule(cPath.c_str())){ |
| 251 | + // the module couldn't be loaded |
| 252 | + logger->log(LOG_LEVEL_ERROR,"Failed to load module %s, skipping!\n",cPath.c_str()); |
| 253 | + } |
| 254 | + } |
| 255 | + } |
| 256 | + next: |
| 257 | + ent = readdir(dir); // next entry |
| 258 | + } |
| 259 | +#endif |
| 260 | +} |
0 commit comments