Changed: #1092 Reliability improvements for 3dsmax nel export
This commit is contained in:
parent
998e5b4c17
commit
7f739bed8a
4 changed files with 115 additions and 22 deletions
|
@ -36,11 +36,18 @@ bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time)
|
||||||
{
|
{
|
||||||
// Result to return
|
// Result to return
|
||||||
bool bRet = false;
|
bool bRet = false;
|
||||||
char tempName[L_tmpnam];
|
char tempFileName[MAX_PATH] = { 0 };
|
||||||
tmpnam(tempName);
|
char tempPathBuffer[MAX_PATH] = { 0 };
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
DWORD dwRetVal = GetTempPathA(MAX_PATH, tempPathBuffer);
|
||||||
|
if (dwRetVal > MAX_PATH || (dwRetVal == 0))
|
||||||
|
nlerror("GetTempPath failed");
|
||||||
|
UINT uRetVal = GetTempFileNameA(tempPathBuffer, TEXT("_nel_export_mesh_"), 0, tempFileName);
|
||||||
|
if (uRetVal == 0)
|
||||||
|
nlerror("GetTempFileName failed");
|
||||||
|
|
||||||
// Eval the object a time
|
// Eval the object a time
|
||||||
ObjectState os = node.EvalWorldState(time);
|
ObjectState os = node.EvalWorldState(time);
|
||||||
|
|
||||||
|
@ -48,7 +55,7 @@ bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time)
|
||||||
if (os.obj)
|
if (os.obj)
|
||||||
{
|
{
|
||||||
// Skeleton shape
|
// Skeleton shape
|
||||||
CSmartPtr<CSkeletonShape> skeletonShape = NULL;
|
CSkeletonShape * skeletonShape = NULL;
|
||||||
TInodePtrInt *mapIdPtr=NULL;
|
TInodePtrInt *mapIdPtr=NULL;
|
||||||
TInodePtrInt mapId;
|
TInodePtrInt mapId;
|
||||||
|
|
||||||
|
@ -69,7 +76,7 @@ bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time)
|
||||||
CExportNel::addSkeletonBindPos (node, boneBindPos);
|
CExportNel::addSkeletonBindPos (node, boneBindPos);
|
||||||
|
|
||||||
// Build the skeleton based on the bind pos information
|
// Build the skeleton based on the bind pos information
|
||||||
_ExportNel->buildSkeletonShape(*skeletonShape.getPtr(), *skeletonRoot, &boneBindPos, mapId, time);
|
_ExportNel->buildSkeletonShape(*skeletonShape, *skeletonRoot, &boneBindPos, mapId, time);
|
||||||
|
|
||||||
// Set the pointer to not NULL
|
// Set the pointer to not NULL
|
||||||
mapIdPtr=&mapId;
|
mapIdPtr=&mapId;
|
||||||
|
@ -83,16 +90,16 @@ bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time)
|
||||||
if (InfoLog)
|
if (InfoLog)
|
||||||
InfoLog->display("Beg buildShape %s \n", node.GetName());
|
InfoLog->display("Beg buildShape %s \n", node.GetName());
|
||||||
// Export in mesh format
|
// Export in mesh format
|
||||||
CSmartPtr<IShape> pShape = _ExportNel->buildShape(node, time, mapIdPtr, true);
|
IShape *pShape = _ExportNel->buildShape(node, time, mapIdPtr, true);
|
||||||
if (InfoLog)
|
if (InfoLog)
|
||||||
InfoLog->display("End buildShape in %d ms \n", timeGetTime()-t);
|
InfoLog->display("End buildShape in %d ms \n", timeGetTime()-t);
|
||||||
|
|
||||||
// Conversion success ?
|
// Conversion success ?
|
||||||
if (pShape.getPtr())
|
if (pShape)
|
||||||
{
|
{
|
||||||
// Open a file
|
// Open a file
|
||||||
COFile file;
|
COFile file;
|
||||||
if (file.open(tempName))
|
if (file.open(tempFileName))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -102,6 +109,9 @@ bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time)
|
||||||
// Serial the shape
|
// Serial the shape
|
||||||
shapeStream.serial(file);
|
shapeStream.serial(file);
|
||||||
|
|
||||||
|
// Close the file
|
||||||
|
file.close();
|
||||||
|
|
||||||
// All is good
|
// All is good
|
||||||
bRet = true;
|
bRet = true;
|
||||||
}
|
}
|
||||||
|
@ -116,29 +126,61 @@ bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
remove(tempName);
|
remove(tempFileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nlwarning("Failed to create file %s", tempName);
|
nlwarning("Failed to create file %s", tempFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the pointer
|
// Delete the pointer
|
||||||
nldebug ("Delete the pointer");
|
nldebug("Delete the pointer");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool tempBRet = bRet;
|
bool tempBRet = bRet;
|
||||||
bRet = false;
|
bRet = false;
|
||||||
pShape = NULL;
|
// delete pShape; // FIXME: there is a delete bug with CMeshMultiLod exported from max!!!
|
||||||
bRet = tempBRet;
|
bRet = tempBRet;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
nlwarning("Failed to delete pShape pointer! Something might be wrong.");
|
nlwarning("Failed to delete pShape pointer! Something might be wrong.");
|
||||||
remove(tempName);
|
remove(tempFileName);
|
||||||
bRet = false;
|
bRet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify the file
|
||||||
|
nldebug("Verify exported shape file");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool tempBRet = bRet;
|
||||||
|
bRet = false;
|
||||||
|
CIFile vf;
|
||||||
|
if (vf.open(tempFileName))
|
||||||
|
{
|
||||||
|
nldebug("File opened, size: %u", vf.getFileSize());
|
||||||
|
CShapeStream s;
|
||||||
|
s.serial(vf);
|
||||||
|
nldebug("Shape serialized");
|
||||||
|
vf.close();
|
||||||
|
nldebug("File closed");
|
||||||
|
delete s.getShapePointer();
|
||||||
|
nldebug("Shape deleted");
|
||||||
|
bRet = tempBRet;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlwarning("Failed to open file: %s", tempFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
nlwarning("Failed to verify shape. Must crash now.");
|
||||||
|
remove(tempFileName);
|
||||||
|
bRet = false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,8 +200,8 @@ bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
CFile::moveFile(sPath, tempName);
|
CFile::moveFile(sPath, tempFileName);
|
||||||
nlinfo("MOVE %s -> %s", tempName, sPath);
|
nlinfo("MOVE %s -> %s", tempFileName, sPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bRet;
|
return bRet;
|
||||||
|
|
|
@ -55,6 +55,9 @@ def_visible_primitive ( mirror_physique, "NelMirrorPhysique" );
|
||||||
def_visible_primitive ( get_file_modification_date, "NeLGetFileModificationDate" );
|
def_visible_primitive ( get_file_modification_date, "NeLGetFileModificationDate" );
|
||||||
def_visible_primitive ( set_file_modification_date, "NeLSetFileModificationDate" );
|
def_visible_primitive ( set_file_modification_date, "NeLSetFileModificationDate" );
|
||||||
|
|
||||||
|
def_visible_primitive ( force_quit_on_msg_displayer, "NelForceQuitOnMsgDisplayer");
|
||||||
|
def_visible_primitive ( force_quit_right_now, "NelForceQuitRightNow");
|
||||||
|
|
||||||
char *sExportShapeErrorMsg = "NeLExportShape [Object] [Filename.shape]";
|
char *sExportShapeErrorMsg = "NeLExportShape [Object] [Filename.shape]";
|
||||||
char *sExportShapeExErrorMsg = "NeLExportShapeEx [Object] [Filename.shape] [bShadow] [bExportLighting] [sLightmapPath] [nLightingLimit] [fLumelSize] [nOverSampling] [bExcludeNonSelected] [bShowLumel]";
|
char *sExportShapeExErrorMsg = "NeLExportShapeEx [Object] [Filename.shape] [bShadow] [bExportLighting] [sLightmapPath] [nLightingLimit] [fLumelSize] [nOverSampling] [bExcludeNonSelected] [bShowLumel]";
|
||||||
char *sExportAnimationErrorMsg = "NelExportAnimation [node array] [Filename.anim] [bool_scene_animation]";
|
char *sExportAnimationErrorMsg = "NelExportAnimation [node array] [Filename.anim] [bool_scene_animation]";
|
||||||
|
@ -933,6 +936,55 @@ Value* set_file_modification_date_cf (Value** arg_list, int count)
|
||||||
return &false_value;
|
return &false_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CSuicideMsgBoxDisplayer : public CMsgBoxDisplayer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CSuicideMsgBoxDisplayer (const char *displayerName = "") : CMsgBoxDisplayer(displayerName) { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Put the string into the file.
|
||||||
|
virtual void doDisplay( const CLog::TDisplayInfo& args, const char *message )
|
||||||
|
{
|
||||||
|
DWORD ec = 0;
|
||||||
|
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
|
||||||
|
GetExitCodeProcess(h, &ec);
|
||||||
|
TerminateProcess(h, ec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Value* force_quit_on_msg_displayer_cf(Value** arg_list, int count)
|
||||||
|
{
|
||||||
|
nlwarning("Enable force quit on NeL report msg displayer");
|
||||||
|
// disable the Windows popup telling that the application aborted and disable the dr watson report.
|
||||||
|
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
||||||
|
putenv("NEL_IGNORE_ASSERT=1");
|
||||||
|
if (NLMISC::DefaultMsgBoxDisplayer || INelContext::getInstance().getDefaultMsgBoxDisplayer())
|
||||||
|
{
|
||||||
|
if (!NLMISC::DefaultMsgBoxDisplayer)
|
||||||
|
NLMISC::DefaultMsgBoxDisplayer = INelContext::getInstance().getDefaultMsgBoxDisplayer();
|
||||||
|
nldebug("Disable NeL report msg displayer");
|
||||||
|
INelContext::getInstance().getAssertLog()->removeDisplayer(NLMISC::DefaultMsgBoxDisplayer);
|
||||||
|
INelContext::getInstance().getErrorLog()->removeDisplayer(NLMISC::DefaultMsgBoxDisplayer);
|
||||||
|
// TODO: Delete original NLMISC::DefaultMsgBoxDisplayer?
|
||||||
|
}
|
||||||
|
NLMISC::DefaultMsgBoxDisplayer = new CSuicideMsgBoxDisplayer("FORCEQUIT_MDB");
|
||||||
|
INelContext::getInstance().setDefaultMsgBoxDisplayer(NLMISC::DefaultMsgBoxDisplayer);
|
||||||
|
INelContext::getInstance().getAssertLog()->addDisplayer(NLMISC::DefaultMsgBoxDisplayer);
|
||||||
|
INelContext::getInstance().getErrorLog()->addDisplayer(NLMISC::DefaultMsgBoxDisplayer);
|
||||||
|
return &true_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* force_quit_right_now_cf(Value** arg_list, int count)
|
||||||
|
{
|
||||||
|
// because quitMAX can fail
|
||||||
|
nlwarning("Force quit");
|
||||||
|
DWORD ec = 0;
|
||||||
|
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
|
||||||
|
GetExitCodeProcess(h, &ec);
|
||||||
|
TerminateProcess(h, ec);
|
||||||
|
return &true_value;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*\
|
/*===========================================================================*\
|
||||||
| MAXScript Plugin Initialization
|
| MAXScript Plugin Initialization
|
||||||
\*===========================================================================*/
|
\*===========================================================================*/
|
||||||
|
|
|
@ -131,7 +131,7 @@ static void copyMultiLodMeshBaseLod0Infos(CMeshBase::CMeshBaseBuild &dst, const
|
||||||
|
|
||||||
// ***************************************************************************
|
// ***************************************************************************
|
||||||
// Export a mesh
|
// Export a mesh
|
||||||
NLMISC::CSmartPtr<NL3D::IShape> CExportNel::buildShape (INode& node, TimeValue time, const TInodePtrInt *nodeMap, bool buildLods)
|
NL3D::IShape *CExportNel::buildShape (INode& node, TimeValue time, const TInodePtrInt *nodeMap, bool buildLods)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Is this a multi lod object ?
|
// Is this a multi lod object ?
|
||||||
|
@ -139,7 +139,7 @@ NLMISC::CSmartPtr<NL3D::IShape> CExportNel::buildShape (INode& node, TimeValue t
|
||||||
|
|
||||||
// Here, we must check what kind of node we can build with this mesh.
|
// Here, we must check what kind of node we can build with this mesh.
|
||||||
// For the time, just Triobj is supported.
|
// For the time, just Triobj is supported.
|
||||||
CSmartPtr<IShape> retShape = NULL;
|
NL3D::IShape *retShape = NULL;
|
||||||
|
|
||||||
// If skinning, disable skin modifier
|
// If skinning, disable skin modifier
|
||||||
if (nodeMap)
|
if (nodeMap)
|
||||||
|
@ -206,7 +206,7 @@ NLMISC::CSmartPtr<NL3D::IShape> CExportNel::buildShape (INode& node, TimeValue t
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Mesh base ?
|
// Mesh base ?
|
||||||
CSmartPtr<CMeshBase> meshBase = NULL;
|
CMeshBase *meshBase = NULL;
|
||||||
|
|
||||||
// Get the node matrix
|
// Get the node matrix
|
||||||
Matrix3 nodeMatrixMax;
|
Matrix3 nodeMatrixMax;
|
||||||
|
@ -317,8 +317,7 @@ NLMISC::CSmartPtr<NL3D::IShape> CExportNel::buildShape (INode& node, TimeValue t
|
||||||
|
|
||||||
|
|
||||||
// Make a CMeshMultiLod mesh object
|
// Make a CMeshMultiLod mesh object
|
||||||
CMeshMultiLod *multiMesh = new CMeshMultiLod;
|
CMeshMultiLod *multiMesh = new CMeshMultiLod; // FIXME: there is a delete bug with CMeshMultiLod exported from max!!!
|
||||||
++multiMesh->crefs; // hack
|
|
||||||
|
|
||||||
// Build it
|
// Build it
|
||||||
multiMesh->build(multiLodBuild);
|
multiMesh->build(multiLodBuild);
|
||||||
|
@ -461,7 +460,7 @@ NLMISC::CSmartPtr<NL3D::IShape> CExportNel::buildShape (INode& node, TimeValue t
|
||||||
enableSkinModifier (node, true);
|
enableSkinModifier (node, true);
|
||||||
|
|
||||||
// Set the dist max for this shape
|
// Set the dist max for this shape
|
||||||
if (retShape.getPtr() && !multiLodObject && buildLods)
|
if (retShape && !multiLodObject && buildLods)
|
||||||
{
|
{
|
||||||
// Get the dist max for this node
|
// Get the dist max for this node
|
||||||
float distmax = getScriptAppData (&node, NEL3D_APPDATA_LOD_DIST_MAX, NEL3D_APPDATA_LOD_DIST_MAX_DEFAULT);
|
float distmax = getScriptAppData (&node, NEL3D_APPDATA_LOD_DIST_MAX, NEL3D_APPDATA_LOD_DIST_MAX_DEFAULT);
|
||||||
|
|
|
@ -292,7 +292,7 @@ public:
|
||||||
*
|
*
|
||||||
* skeletonShape must be NULL if no bones.
|
* skeletonShape must be NULL if no bones.
|
||||||
*/
|
*/
|
||||||
NLMISC::CSmartPtr<NL3D::IShape> buildShape (INode& node, TimeValue time, const TInodePtrInt *nodeMap,
|
NL3D::IShape* buildShape (INode& node, TimeValue time, const TInodePtrInt *nodeMap,
|
||||||
bool buildLods);
|
bool buildLods);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue