Files
2025-12-15 23:22:33 +08:00

284 lines
9.6 KiB
C++

/***********************************************************************************************************************
*
* 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 <memory>
#include <new> // for exception-throwing new
#ifdef __ANDROID__
# include <android/log.h>
# include <dlfcn.h>
# define INITIALIZE_A3D_API
# include <A3DSDKIncludes.h>
# 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 <A3DSDKIncludes.h>
# 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