/*********************************************************************************************************************** * * Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc. * The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret * as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event * of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized * employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the * scope and manner of such use. * ***********************************************************************************************************************/ #include #include // for exception-throwing new #ifdef __ANDROID__ # include # include # define INITIALIZE_A3D_API # include # undef INITIALIZE_A3D_API # define JNI_LOG_TAG "SAMPLE PRC 2 XML" # define LOGI(...) __android_log_print(ANDROID_LOG_INFO, JNI_LOG_TAG, __VA_ARGS__) # define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, JNI_LOG_TAG, __VA_ARGS__) #endif // __ANDROID__ #ifdef __APPLE__ # include "TargetConditionals.h" # if TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1 # define APPLE_IOS # include # endif #endif #include "PRC2XML.h" //###################################################################################################################### // reads the PRC file and dumps information into XML format A3DStatus ReadFile(A3DSDKHOOPSExchangeLoader& sHoopsExchangeLoader, A3DImport& sImport, _TiXmlElement* treatment) { const A3DStatus iRet = sHoopsExchangeLoader.Import(sImport); if(iRet != A3D_SUCCESS && iRet != A3D_LOAD_MULTI_MODELS_CADFILE && iRet != A3D_LOAD_MISSING_COMPONENTS) return iRet; A3DAsmModelFile* pModelFile = sHoopsExchangeLoader.m_psModelFile; // Retrieve physical properties A3DPhysicalPropertiesData sPhysPropsData; A3D_INITIALIZE_DATA(A3DPhysicalPropertiesData, sPhysPropsData); A3DStatus iRetP = A3DComputeModelFilePhysicalProperties(pModelFile, &sPhysPropsData); std::unique_ptr<_TiXmlElement> physicalprops(new _TiXmlElement("ComputePhysicalProps")); if (iRetP == A3D_SUCCESS) { physicalprops->SetDoubleAttribute("m_sGravityCenter.m_dX", sPhysPropsData.m_sGravityCenter.m_dX); physicalprops->SetDoubleAttribute("m_sGravityCenter.m_dY", sPhysPropsData.m_sGravityCenter.m_dY); physicalprops->SetDoubleAttribute("m_sGravityCenter.m_dZ", sPhysPropsData.m_sGravityCenter.m_dZ); physicalprops->SetDoubleAttribute("m_dSurface", sPhysPropsData.m_dSurface); physicalprops->SetDoubleAttribute("m_bVolumeComputed", sPhysPropsData.m_bVolumeComputed); physicalprops->SetDoubleAttribute("m_dVolume", sPhysPropsData.m_dVolume); } else { physicalprops->SetAttribute("error", A3DMiscGetErrorMsg(iRetP)); } treatment->LinkEndChild(physicalprops.release()); #ifndef APPLE_IOS // the following code triggers a SIGSTOP on iOS // Retrieve files path from model files A3DUns32 nbFiles = 0, nbAssemblyFiles = 0, nbMissingFiles = 0; A3DUTF8Char** ppPaths = NULL, ** ppAssemblyPaths = NULL, ** ppMissingPaths = NULL; struct ModelFileGuard { A3DAsmModelFile*& m_psModelFile; explicit ModelFileGuard(A3DAsmModelFile*& pModelFile): m_psModelFile(pModelFile) {} ~ModelFileGuard() { A3DAsmModelFileDelete(m_psModelFile); m_psModelFile = NULL; } } const sGuard(sHoopsExchangeLoader.m_psModelFile); #ifdef __ANDROID__ try { #endif CHECK_RET(A3DAsmGetFilesPathFromModelFile( sHoopsExchangeLoader.m_psModelFile, &nbFiles, &ppPaths, &nbAssemblyFiles, &ppAssemblyPaths, &nbMissingFiles, &ppMissingPaths)); #ifdef __ANDROID__ } catch(std::exception const& e) { LOGE("%s\n", e.what()); return iRet; } #endif std::unique_ptr<_TiXmlElement> allFilesPaths(new _TiXmlElement("A3DAsmFilesPathFromModelFile")); allFilesPaths->SetAttribute("nbFiles" , (int)nbFiles); allFilesPaths->SetAttribute("nbAssemblyFiles", (int)nbAssemblyFiles); allFilesPaths->SetAttribute("nbMissingFiles" , (int)nbMissingFiles); for (A3DUns32 ui = 0; ui < nbFiles; ui++) { std::unique_ptr<_TiXmlElement> filePaths(new _TiXmlElement("Filepaths")); filePaths->SetAttribute("m_FilePaths", ppPaths[ui]); allFilesPaths->LinkEndChild(filePaths.release()); } for (A3DUns32 uj = 0; uj < nbAssemblyFiles; uj++) { std::unique_ptr<_TiXmlElement> assemblyFilePaths(new _TiXmlElement("AssemblyFilePaths")); assemblyFilePaths->SetAttribute("m_AssemblyFilePaths", ppAssemblyPaths[uj]); allFilesPaths->LinkEndChild(assemblyFilePaths.release()); } for (A3DUns32 uk = 0; uk < nbMissingFiles; uk++) { std::unique_ptr<_TiXmlElement> missingFilePaths(new _TiXmlElement("MissingFilePaths")); missingFilePaths->SetAttribute("m_nbMissingFiles", ppMissingPaths[uk]); allFilesPaths->LinkEndChild(missingFilePaths.release()); } treatment->LinkEndChild(allFilesPaths.release()); CHECK_RET(A3DAsmGetFilesPathFromModelFile(NULL, &nbFiles, &ppPaths, &nbAssemblyFiles, &ppAssemblyPaths, &nbMissingFiles, &ppMissingPaths)); #endif // !defined(APPLE_IOS) A3DGlobal* pGlobal = NULL; CHECK_RET(A3DGlobalGetPointer(&pGlobal)); traverseGlobal(pGlobal, treatment); traverseModel(pModelFile, treatment); traverseFonts(treatment); return iRet; } //###################################################################################################################### A3DVoid _InitializeFontsArray(); //###################################################################################################################### A3DVoid _TerminateFontsArray(); //###################################################################################################################### A3DStatus ProcessFile( A3DSDKHOOPSExchangeLoader& sHoopsExchangeLoader, A3DImport& sImport, const MY_CHAR* pcPRCFile, const MY_CHAR* pcXMLFile, bool bDumpPictures) { A3DUTF8Char sPRCFileUTF8[_MAX_PATH]; A3DUTF8Char sXMLFileUTF8[_MAX_PATH]; #ifdef _MSC_VER A3DMiscUTF16ToUTF8(pcPRCFile, sPRCFileUTF8); A3DMiscUTF16ToUTF8(pcXMLFile, sXMLFileUTF8); #else MY_STRCPY(sPRCFileUTF8, pcPRCFile); MY_STRCPY(sXMLFileUTF8, pcXMLFile); #endif std::unique_ptr<_TiXmlDocument> doc; try { doc.reset(new _TiXmlDocument); doc->SetCondenseWhiteSpace(false); std::unique_ptr<_TiXmlComment> comment(new _TiXmlComment("XML dump from PRC file")); doc->LinkEndChild(comment.release()); A3DInt32 iMajorVersion = 0, iMinorVersion = 0; CHECK_RET(A3DDllGetVersion(&iMajorVersion, &iMinorVersion)); std::unique_ptr<_TiXmlElement> treatment(new _TiXmlElement("TREATMENT")); treatment->SetAttribute("MajorVersion", iMajorVersion); treatment->SetAttribute("MinorVersion", iMinorVersion); treatment->SetAttribute("PRCFile" , sPRCFileUTF8); _InitializeFontsArray(); // if specified, dump pictures from texture material, in an "img" folder next to the XML output if(bDumpPictures) setTextureDirectory(pcXMLFile); TEST_RET(ReadFile(sHoopsExchangeLoader, sImport, treatment.get())) doc->LinkEndChild(treatment.release()); doc->SaveFile(sXMLFileUTF8); _TerminateFontsArray(); return A3D_SUCCESS; } catch(const std::bad_alloc&) { PrintConstLogError(NULL, "std::bad_alloc exception caught\n"); if (doc.get()) // try to save what has already been generated doc->SaveFile(sXMLFileUTF8); return A3D_ERROR; } } #if ( !defined(__ANDROID__) && !defined(APPLE_IOS) ) || TARGET_OS_MACCATALYST == 1 //###################################################################################################################### void ShowUsage(MY_CHAR** ppcArgv) { if (ppcArgv) MY_PRINTF2("Usage:\n %s [input CAD file] [output XML file] [output LOG file] [-dumppictures]\n", ppcArgv[0]); else MY_PRINTF("Usage:\n PRC2XML [input CAD file] [output XML file] [output LOG file] [-dumppictures]\n"); MY_PRINTF(" Default output XML file is [input CAD file].xml\n"); MY_PRINTF(" Default output LOG file is [output XML file]_Log.txt\n"); MY_PRINTF(" If -dumppictures is specified, pictures from texture materials will be exported in an \"img\" folder, next to the XML output\n\n"); } //###################################################################################################################### bool ParseArgs(A3DInt32 iArgc, MY_CHAR** ppcArgv, MY_CHAR(&acSrcFileName)[_MAX_PATH * 2], MY_CHAR(&acDstFileName)[_MAX_PATH * 2], MY_CHAR(&acLogFileName)[_MAX_PATH * 2], unsigned& uPrc2xmlFlagArgs) { if (iArgc == 2) { if (!MY_STRCMP(ppcArgv[1], "-help")) return false; else if (!MY_STRCMP(ppcArgv[1], "-usage")) return false; } acSrcFileName[0] = '\0'; acDstFileName[0] = '\0'; acLogFileName[0] = '\0'; // parse arguments A3DInt32 iPositionalArg = 0; for (A3DInt32 iArg = 1; iArg < iArgc; ++iArg) { if (!MY_STRCMP(ppcArgv[iArg], "-dumppictures")) { uPrc2xmlFlagArgs |= DUMPPICTURES; } else if (!MY_STRCMP(ppcArgv[iArg], "-dumprelationships")) { uPrc2xmlFlagArgs |= DUMPRELATIONSHIPS; } else if ('-' == ppcArgv[iArg][0]) { return false; } else { switch (iPositionalArg) { case 0: MY_STRCPY(acSrcFileName, ppcArgv[iArg]); break; case 1: MY_STRCPY(acDstFileName, ppcArgv[iArg]); break; case 2: MY_STRCPY(acLogFileName, ppcArgv[iArg]); break; default: break; } ++iPositionalArg; } } // init default values if (acSrcFileName[0] == '\0') MY_STRCPY(acSrcFileName, DEFAULT_INPUT_CAD); if (acDstFileName[0] == '\0') MY_SPRINTF(acDstFileName, "%s.xml", acSrcFileName); if (acLogFileName[0] == '\0') MY_SPRINTF(acLogFileName, "%s_Log.txt", acDstFileName); return true; } #endif