Changed: #929 Some reliability fixes for the max export plugin.

This commit is contained in:
kaetemi 2010-08-25 23:36:29 +02:00
parent b5f6188757
commit 4cf6235095
18 changed files with 914 additions and 765 deletions

View file

@ -17,6 +17,7 @@
#include "std_afx.h" #include "std_afx.h"
#include "nel_export.h" #include "nel_export.h"
#include "nel/misc/file.h" #include "nel/misc/file.h"
#include "nel/misc/path.h"
#include "nel/3d/shape.h" #include "nel/3d/shape.h"
#include "nel/3d/animation.h" #include "nel/3d/animation.h"
#include "nel/3d/skeleton_shape.h" #include "nel/3d/skeleton_shape.h"
@ -34,94 +35,133 @@ using namespace NLMISC;
bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time) 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];
// Eval the object a time tmpnam(tempName);
ObjectState os = node.EvalWorldState(time);
try
// Object exist ?
if (os.obj)
{ {
// Skeleton shape // Eval the object a time
CSkeletonShape *skeletonShape=NULL; ObjectState os = node.EvalWorldState(time);
TInodePtrInt *mapIdPtr=NULL;
TInodePtrInt mapId;
// If model skinned ? // Object exist ?
if (CExportNel::isSkin (node)) if (os.obj)
{ {
// Create a skeleton // Skeleton shape
INode *skeletonRoot=CExportNel::getSkeletonRootBone (node); CSmartPtr<CSkeletonShape> skeletonShape = NULL;
TInodePtrInt *mapIdPtr=NULL;
TInodePtrInt mapId;
// Skeleton exist ? // If model skinned ?
if (skeletonRoot) if (CExportNel::isSkin (node))
{ {
// Build a skeleton // Create a skeleton
skeletonShape=new CSkeletonShape(); INode *skeletonRoot = CExportNel::getSkeletonRootBone(node);
// Add skeleton bind pos info // Skeleton exist ?
CExportNel::mapBoneBindPos boneBindPos; if (skeletonRoot)
CExportNel::addSkeletonBindPos (node, boneBindPos); {
// Build a skeleton
skeletonShape = new CSkeletonShape();
// Build the skeleton based on the bind pos information // Add skeleton bind pos info
_ExportNel->buildSkeletonShape (*skeletonShape, *skeletonRoot, &boneBindPos, mapId, time); CExportNel::mapBoneBindPos boneBindPos;
CExportNel::addSkeletonBindPos (node, boneBindPos);
// Set the pointer to not NULL // Build the skeleton based on the bind pos information
mapIdPtr=&mapId; _ExportNel->buildSkeletonShape(*skeletonShape.getPtr(), *skeletonRoot, &boneBindPos, mapId, time);
// Erase the skeleton // Set the pointer to not NULL
if (skeletonShape) mapIdPtr=&mapId;
delete skeletonShape;
// Erase the skeleton
skeletonShape = NULL;
}
} }
}
DWORD t = timeGetTime();
DWORD t = timeGetTime(); 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
COFile file;
if (file.open (sPath))
{ {
// Open a file
COFile file;
if (file.open(tempName))
{
try
{
// Create a streamable shape
CShapeStream shapeStream(pShape);
// Serial the shape
shapeStream.serial(file);
// All is good
bRet = true;
}
catch (...)
{
nlwarning("Shape serialization failed!");
try
{
file.close();
}
catch (...)
{
}
remove(tempName);
}
}
else
{
nlwarning("Failed to create file %s", tempName);
}
// Delete the pointer
nldebug ("Delete the pointer");
try try
{ {
// Create a streamable shape bool tempBRet = bRet;
CShapeStream shapeStream (pShape); bRet = false;
pShape = NULL;
// Serial the shape bRet = tempBRet;
shapeStream.serial (file);
// All is good
bRet=true;
} }
catch (...) catch (...)
{ {
nlwarning("Shape serialization failed!"); nlwarning("Failed to delete pShape pointer! Something might be wrong.");
file.close(); remove(tempName);
remove(sPath); bRet = false;
} }
} }
// Delete the pointer
nldebug ("Delete the pointer");
try
{
// memory leak, fixme
// delete pShape;
}
catch (...)
{
nlwarning("Failed to delete pShape pointer! Something might be wrong.");
}
} }
} }
catch (...)
{
nlwarning("Fatal exception at CNelExport::exportMesh.");
bRet = false;
}
if (bRet)
{
try
{
remove(sPath);
}
catch (...)
{
}
CFile::moveFile(sPath, tempName);
nlinfo("MOVE %s -> %s", tempName, sPath);
}
return bRet; return bRet;
} }

View file

@ -77,7 +77,8 @@ SLightBuild::SLightBuild()
bool SLightBuild::canConvertFromMaxLight (INode *node, TimeValue tvTime) bool SLightBuild::canConvertFromMaxLight (INode *node, TimeValue tvTime)
{ {
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node->EvalWorldState(tvTime).obj; ObjectState os = node->EvalWorldState(tvTime);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (!obj) if (!obj)
@ -98,7 +99,7 @@ bool SLightBuild::canConvertFromMaxLight (INode *node, TimeValue tvTime)
return false; return false;
if( deleteIt ) if( deleteIt )
maxLight->DeleteMe(); maxLight->MaybeAutoDelete();
return true; return true;
} }
@ -107,7 +108,8 @@ bool SLightBuild::canConvertFromMaxLight (INode *node, TimeValue tvTime)
void SLightBuild::convertFromMaxLight (INode *node,TimeValue tvTime) void SLightBuild::convertFromMaxLight (INode *node,TimeValue tvTime)
{ {
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node->EvalWorldState(tvTime).obj; ObjectState os = node->EvalWorldState(tvTime);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (!obj) return; if (!obj) return;
@ -295,7 +297,7 @@ void SLightBuild::convertFromMaxLight (INode *node,TimeValue tvTime)
this->rSoftShadowConeLength = (float)atof(sTmp.c_str()); this->rSoftShadowConeLength = (float)atof(sTmp.c_str());
if( deleteIt ) if( deleteIt )
maxLight->DeleteMe(); maxLight->MaybeAutoDelete();
} }
// *********************************************************************************************** // ***********************************************************************************************
@ -2401,7 +2403,10 @@ bool CExportNel::calculateLM( CMesh::CMeshBuild *pZeMeshBuild, CMeshBase::CMeshB
TempPlanes[nPlaneNb]->copyFirstLayerTo(*AllPlanes[AllPlanesPrevSize+nPlaneNb],(uint8)nLight); TempPlanes[nPlaneNb]->copyFirstLayerTo(*AllPlanes[AllPlanesPrevSize+nPlaneNb],(uint8)nLight);
for( nPlaneNb = 0; nPlaneNb < (sint)FaceGroupByPlane.size(); ++nPlaneNb ) for( nPlaneNb = 0; nPlaneNb < (sint)FaceGroupByPlane.size(); ++nPlaneNb )
{
delete TempPlanes[nPlaneNb]; delete TempPlanes[nPlaneNb];
TempPlanes[nPlaneNb] = NULL;
}
} }
// Next group of face with the same smooth group and the same material // Next group of face with the same smooth group and the same material
@ -2497,6 +2502,7 @@ bool CExportNel::calculateLM( CMesh::CMeshBuild *pZeMeshBuild, CMeshBase::CMeshB
MoveFaceUV1( AllPlanes[i]->faces.begin(), AllPlanes[i]->faces.size(), MoveFaceUV1( AllPlanes[i]->faces.begin(), AllPlanes[i]->faces.size(),
AllPlanes[i]->x, AllPlanes[i]->y ); AllPlanes[i]->x, AllPlanes[i]->y );
delete AllPlanes[i]; delete AllPlanes[i];
AllPlanes[i] = NULL;
} }
// Save the lightmap // Save the lightmap

View file

@ -264,6 +264,7 @@ void CExportNel::addParticleSystemTracks(CAnimation& animation, INode& node, con
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -281,6 +282,7 @@ void CExportNel::addParticleSystemTracks(CAnimation& animation, INode& node, con
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -325,6 +327,7 @@ void CExportNel::addNodeTracks (CAnimation& animation, INode& node, const char*
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -348,6 +351,7 @@ void CExportNel::addNodeTracks (CAnimation& animation, INode& node, const char*
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -371,6 +375,7 @@ void CExportNel::addNodeTracks (CAnimation& animation, INode& node, const char*
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -389,6 +394,7 @@ void CExportNel::addNodeTracks (CAnimation& animation, INode& node, const char*
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -413,6 +419,7 @@ void CExportNel::addNodeTracks (CAnimation& animation, INode& node, const char*
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -443,6 +450,7 @@ void CExportNel::addNodeTracks (CAnimation& animation, INode& node, const char*
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -541,7 +549,8 @@ void CExportNel::addLightTracks (NL3D::CAnimation& animation, INode& node, const
{ {
CExportDesc desc; CExportDesc desc;
Object *obj = node.EvalWorldState(0).obj; ObjectState os = node.EvalWorldState(0);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (!obj) if (!obj)
@ -567,6 +576,7 @@ void CExportNel::addLightTracks (NL3D::CAnimation& animation, INode& node, const
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -609,6 +619,7 @@ void CExportNel::addMorphTracks (NL3D::CAnimation& animation, INode& node, const
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -639,6 +650,7 @@ void CExportNel::addObjTracks (CAnimation& animation, Object& obj, const char* p
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -681,6 +693,7 @@ void CExportNel::addMtlTracks (CAnimation& animation, Mtl& mtl, const char* pare
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -705,6 +718,7 @@ void CExportNel::addMtlTracks (CAnimation& animation, Mtl& mtl, const char* pare
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -731,6 +745,7 @@ void CExportNel::addMtlTracks (CAnimation& animation, Mtl& mtl, const char* pare
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -755,6 +770,7 @@ void CExportNel::addMtlTracks (CAnimation& animation, Mtl& mtl, const char* pare
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -779,6 +795,7 @@ void CExportNel::addMtlTracks (CAnimation& animation, Mtl& mtl, const char* pare
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -862,6 +879,7 @@ void CExportNel::addTexTracks (CAnimation& animation, Texmap& tex, uint stage, c
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -884,6 +902,7 @@ void CExportNel::addTexTracks (CAnimation& animation, Texmap& tex, uint stage, c
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -906,6 +925,7 @@ void CExportNel::addTexTracks (CAnimation& animation, Texmap& tex, uint stage, c
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -928,6 +948,7 @@ void CExportNel::addTexTracks (CAnimation& animation, Texmap& tex, uint stage, c
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -950,6 +971,7 @@ void CExportNel::addTexTracks (CAnimation& animation, Texmap& tex, uint stage, c
if (animation.getTrackByName (name.c_str())) if (animation.getTrackByName (name.c_str()))
{ {
delete pTrack; delete pTrack;
pTrack = NULL;
} }
else else
{ {
@ -2319,7 +2341,7 @@ void CSSSBuild::compile(NL3D::CAnimation &dest, const char* sBaseName)
{ {
// no keys added // no keys added
delete finalTrack; delete finalTrack;
finalTrack= NULL; finalTrack = NULL;
} }

View file

@ -60,7 +60,8 @@ CCollisionMeshBuild* CExportNel::createCollisionMeshBuild(std::vector<INode *> &
for (node=0; node<nodes.size(); ++node) for (node=0; node<nodes.size(); ++node)
{ {
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = nodes[node]->EvalWorldState(tvTime).obj; ObjectState os = nodes[node]->EvalWorldState(tvTime);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
@ -70,72 +71,76 @@ CCollisionMeshBuild* CExportNel::createCollisionMeshBuild(std::vector<INode *> &
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0));
// get the mesh name if (tri)
uint meshId = rootMeshNames.size();
rootMeshNames.push_back(nodes[node]->GetName());
bool collision = getScriptAppData (nodes[node], NEL3D_APPDATA_COLLISION, 0) != 0;
bool exterior = getScriptAppData (nodes[node], NEL3D_APPDATA_COLLISION_EXTERIOR, 0) != 0;
bool deleteIt=false;
if (collision)
{ {
// Note that the TriObject should only be deleted // get the mesh name
// if the pointer to it is not equal to the object uint meshId = rootMeshNames.size();
// pointer that called ConvertToType() rootMeshNames.push_back(nodes[node]->GetName());
if (obj != tri) bool collision = getScriptAppData (nodes[node], NEL3D_APPDATA_COLLISION, 0) != 0;
deleteIt = true; bool exterior = getScriptAppData (nodes[node], NEL3D_APPDATA_COLLISION_EXTERIOR, 0) != 0;
uint i; bool deleteIt=false;
Mesh &mesh = tri->GetMesh(); if (collision)
// Get the object matrix
CMatrix ToWorldSpace;
Matrix3 verticesToWorld = nodes[node]->GetObjectTM(tvTime);
convertMatrix (ToWorldSpace, verticesToWorld);
// Convert the vertices
for (i=0; i<(uint)mesh.numVerts; ++i)
{ {
Point3 v=mesh.verts[i]; // Note that the TriObject should only be deleted
CVector vv=ToWorldSpace*CVector (v.x, v.y, v.z); // if the pointer to it is not equal to the object
pCollisionMeshBuild->Vertices.push_back(vv); // pointer that called ConvertToType()
rootMeshVertices.push_back(node); if (obj != tri)
deleteIt = true;
uint i;
Mesh &mesh = tri->GetMesh();
// Get the object matrix
CMatrix ToWorldSpace;
Matrix3 verticesToWorld = nodes[node]->GetObjectTM(tvTime);
convertMatrix (ToWorldSpace, verticesToWorld);
// Convert the vertices
for (i=0; i<(uint)mesh.numVerts; ++i)
{
Point3 v=mesh.verts[i];
CVector vv=ToWorldSpace*CVector (v.x, v.y, v.z);
pCollisionMeshBuild->Vertices.push_back(vv);
rootMeshVertices.push_back(node);
}
uint maxMatId = 0;
// Convert the faces
for (i=0; i<(uint)mesh.numFaces; ++i)
{
facesRootMeshesInfo.push_back(make_pair(meshId, i));
pCollisionMeshBuild->Faces.resize(pCollisionMeshBuild->Faces.size()+1);
pCollisionMeshBuild->Faces.back().V[0] = mesh.faces[i].v[0]+totalVertices;
pCollisionMeshBuild->Faces.back().V[1] = mesh.faces[i].v[1]+totalVertices;
pCollisionMeshBuild->Faces.back().V[2] = mesh.faces[i].v[2]+totalVertices;
pCollisionMeshBuild->Faces.back().Visibility[0] = ((mesh.faces[i].flags & EDGE_B) != 0);
pCollisionMeshBuild->Faces.back().Visibility[1] = ((mesh.faces[i].flags & EDGE_C) != 0);
pCollisionMeshBuild->Faces.back().Visibility[2] = ((mesh.faces[i].flags & EDGE_A) != 0);
uint32 maxMaterialId = mesh.faces[i].getMatID();
if (!exterior && maxMaterialId > maxMatId)
maxMatId = maxMaterialId;
sint32 sid = (exterior) ? -1 : totalSurfaces+maxMaterialId;
pCollisionMeshBuild->Faces.back().Surface = sid;
pCollisionMeshBuild->Faces.back().Material = maxMaterialId;
}
totalVertices = pCollisionMeshBuild->Vertices.size();
totalFaces = pCollisionMeshBuild->Faces.size();
totalSurfaces += maxMatId+1;
} }
uint maxMatId = 0; // Delete the triObject if we should...
if (deleteIt)
tri->MaybeAutoDelete();
// Convert the faces
for (i=0; i<(uint)mesh.numFaces; ++i)
{
facesRootMeshesInfo.push_back(make_pair(meshId, i));
pCollisionMeshBuild->Faces.resize(pCollisionMeshBuild->Faces.size()+1);
pCollisionMeshBuild->Faces.back().V[0] = mesh.faces[i].v[0]+totalVertices;
pCollisionMeshBuild->Faces.back().V[1] = mesh.faces[i].v[1]+totalVertices;
pCollisionMeshBuild->Faces.back().V[2] = mesh.faces[i].v[2]+totalVertices;
pCollisionMeshBuild->Faces.back().Visibility[0] = ((mesh.faces[i].flags & EDGE_B) != 0);
pCollisionMeshBuild->Faces.back().Visibility[1] = ((mesh.faces[i].flags & EDGE_C) != 0);
pCollisionMeshBuild->Faces.back().Visibility[2] = ((mesh.faces[i].flags & EDGE_A) != 0);
uint32 maxMaterialId = mesh.faces[i].getMatID();
if (!exterior && maxMaterialId > maxMatId)
maxMatId = maxMaterialId;
sint32 sid = (exterior) ? -1 : totalSurfaces+maxMaterialId;
pCollisionMeshBuild->Faces.back().Surface = sid;
pCollisionMeshBuild->Faces.back().Material = maxMaterialId;
}
totalVertices = pCollisionMeshBuild->Vertices.size();
totalFaces = pCollisionMeshBuild->Faces.size();
totalSurfaces += maxMatId+1;
} }
// Delete the triObject if we should...
if (deleteIt)
tri->DeleteMe();
} }
} }
} }
@ -436,6 +441,7 @@ void CExportNel::computeCollisionRetrieverFromScene(TimeValue time,
// free the CCollisionMeshBuild. // free the CCollisionMeshBuild.
delete pCmb; delete pCmb;
pCmb = NULL;
// does igname match prefix/suffix??? // does igname match prefix/suffix???
if(igname.find(igNamePrefix)==0) if(igname.find(igNamePrefix)==0)

View file

@ -200,7 +200,8 @@ void CExportNel::getLights (std::vector<CLight>& vectLight, TimeValue time, INod
node=_Ip->GetRootNode(); node=_Ip->GetRootNode();
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node->EvalWorldState(time).obj; ObjectState os = node->EvalWorldState(time);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
@ -235,9 +236,9 @@ void CExportNel::getLights (std::vector<CLight>& vectLight, TimeValue time, INod
// Add the light in the list // Add the light in the list
vectLight.push_back (nelLight); vectLight.push_back (nelLight);
// Delete the triObject if we should... // Delete the GenLight if we should...
if (deleteIt) if (deleteIt)
maxLight->DeleteMe(); maxLight->MaybeAutoDelete();
} }
} }

View file

@ -43,7 +43,8 @@ bool CExportNel::buildLodCharacter (NL3D::CLodCharacterShapeBuild& lodBuild, IN
return false; return false;
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node.EvalWorldState(time).obj; ObjectState os = node.EvalWorldState(time);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
@ -55,129 +56,131 @@ bool CExportNel::buildLodCharacter (NL3D::CLodCharacterShapeBuild& lodBuild, IN
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0));
if (tri)
{
// Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt=false;
if (obj != tri)
deleteIt = true;
// Note that the TriObject should only be deleted // Get the node matrix
// if the pointer to it is not equal to the object Matrix3 nodeMatrixMax;
// pointer that called ConvertToType() CMatrix nodeMatrix;
bool deleteIt=false; getLocalMatrix (nodeMatrixMax, node, time);
if (obj != tri) convertMatrix (nodeMatrix, nodeMatrixMax);
deleteIt = true;
// Get the node matrix
Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, time);
convertMatrix (nodeMatrix, nodeMatrixMax);
// build the shape // build the shape
{ {
// Array of name for the material // Array of name for the material
CMaxMeshBaseBuild maxBaseBuild; CMaxMeshBaseBuild maxBaseBuild;
// Fill the build interface of CMesh // Fill the build interface of CMesh
CMeshBase::CMeshBaseBuild buildBaseMesh; CMeshBase::CMeshBaseBuild buildBaseMesh;
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, nodeMatrix); buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, nodeMatrix);
CMesh::CMeshBuild buildMesh; CMesh::CMeshBuild buildMesh;
buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, nodeMap); buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, nodeMap);
/* Build a mesh. (duplicate UV/normals) /* Build a mesh. (duplicate UV/normals)
Use a CMeshMRM for an historic reason: simpler because don't use "matrix blocks". Use a CMeshMRM for an historic reason: simpler because don't use "matrix blocks".
*/ */
CMRMParameters mrmParams; CMRMParameters mrmParams;
CMeshMRM meshMRM; CMeshMRM meshMRM;
// To avoid heavy MRM compute, ask for only one lod (=> no poly reduction) // To avoid heavy MRM compute, ask for only one lod (=> no poly reduction)
mrmParams.Divisor= 1; mrmParams.Divisor= 1;
mrmParams.NLods= 1; mrmParams.NLods= 1;
meshMRM.build (buildBaseMesh, buildMesh, std::vector<CMesh::CMeshBuild*>(), mrmParams); meshMRM.build (buildBaseMesh, buildMesh, std::vector<CMesh::CMeshBuild*>(), mrmParams);
const CMeshMRMGeom &meshMRMGeom= meshMRM.getMeshGeom(); const CMeshMRMGeom &meshMRMGeom= meshMRM.getMeshGeom();
nlassert(meshMRMGeom.getNbLod()==1); nlassert(meshMRMGeom.getNbLod()==1);
// Build the lodBuild with the mesh // Build the lodBuild with the mesh
const CVertexBuffer &VB= meshMRMGeom.getVertexBuffer(); const CVertexBuffer &VB= meshMRMGeom.getVertexBuffer();
uint32 format= VB.getVertexFormat(); uint32 format= VB.getVertexFormat();
uint numVerts= VB.getNumVertices(); uint numVerts= VB.getNumVertices();
// The mesh must have at least skinning. // The mesh must have at least skinning.
if( (format & CVertexBuffer::PositionFlag) && meshMRMGeom.isSkinned() ) if( (format & CVertexBuffer::PositionFlag) && meshMRMGeom.isSkinned() )
{
uint i;
CVertexBufferRead vba;
VB.lock (vba);
// build vertices and skinWeights
lodBuild.Vertices.resize(numVerts);
for(i=0;i<numVerts;i++)
lodBuild.Vertices[i]= *(const CVector*)vba.getVertexCoordPointer(i);
// copy skinWeights
lodBuild.SkinWeights= meshMRMGeom.getSkinWeights();
nlassert(lodBuild.SkinWeights.size() == numVerts);
// build UVs and normals
lodBuild.UVs.clear();
lodBuild.Normals.clear();
lodBuild.UVs.resize(numVerts, CUV(0,0));
lodBuild.Normals.resize(numVerts, CVector::K);
if( format & CVertexBuffer::TexCoord0Flag )
{ {
uint i;
CVertexBufferRead vba;
VB.lock (vba);
// build vertices and skinWeights
lodBuild.Vertices.resize(numVerts);
for(i=0;i<numVerts;i++) for(i=0;i<numVerts;i++)
lodBuild.UVs[i]= *(const CUV*)vba.getTexCoordPointer(i); lodBuild.Vertices[i]= *(const CVector*)vba.getVertexCoordPointer(i);
} // copy skinWeights
if( format & CVertexBuffer::NormalFlag ) lodBuild.SkinWeights= meshMRMGeom.getSkinWeights();
{ nlassert(lodBuild.SkinWeights.size() == numVerts);
for(i=0;i<numVerts;i++)
lodBuild.Normals[i]= *(const CVector*)vba.getNormalCoordPointer(i);
}
// build triangles. // build UVs and normals
std::vector<bool> triangleSelection; lodBuild.UVs.clear();
lodBuild.TriangleIndices.resize(buildMesh.Faces.size() * 3); lodBuild.Normals.clear();
triangleSelection.resize(buildMesh.Faces.size(), false); lodBuild.UVs.resize(numVerts, CUV(0,0));
uint dstTriIdx= 0; lodBuild.Normals.resize(numVerts, CVector::K);
for(i=0;i<meshMRMGeom.getNbRdrPass(0);i++) if( format & CVertexBuffer::TexCoord0Flag )
{
const CIndexBuffer &pb= meshMRMGeom.getRdrPassPrimitiveBlock(0, i);
CIndexBufferRead iba;
pb.lock (iba);
nlassert(dstTriIdx+pb.getNumIndexes() <= lodBuild.TriangleIndices.size());
// copy the index block
uint32 *dst= &lodBuild.TriangleIndices[dstTriIdx];
if(pb.getFormat()==CIndexBuffer::Indices32)
memcpy(dst, iba.getPtr(), pb.getNumIndexes()*sizeof(uint32));
else
{ {
nlassert(pb.getFormat()==CIndexBuffer::Indices16); for(i=0;i<numVerts;i++)
uint16 *src= (uint16*)iba.getPtr(); lodBuild.UVs[i]= *(const CUV*)vba.getTexCoordPointer(i);
for(uint n=pb.getNumIndexes();n>0;--n)
*(dst++)=*(src++);
} }
// if the material of this pass is the 0th material, flag tris for TextureInfo selection if( format & CVertexBuffer::NormalFlag )
if(meshMRMGeom.getRdrPassMaterial(0,i)==0)
{ {
for(uint tri= dstTriIdx/3; tri<dstTriIdx/3+pb.getNumIndexes()/3; tri++) for(i=0;i<numVerts;i++)
triangleSelection[tri]= true; lodBuild.Normals[i]= *(const CVector*)vba.getNormalCoordPointer(i);
} }
// next
dstTriIdx+= pb.getNumIndexes(); // build triangles.
std::vector<bool> triangleSelection;
lodBuild.TriangleIndices.resize(buildMesh.Faces.size() * 3);
triangleSelection.resize(buildMesh.Faces.size(), false);
uint dstTriIdx= 0;
for(i=0;i<meshMRMGeom.getNbRdrPass(0);i++)
{
const CIndexBuffer &pb= meshMRMGeom.getRdrPassPrimitiveBlock(0, i);
CIndexBufferRead iba;
pb.lock (iba);
nlassert(dstTriIdx+pb.getNumIndexes() <= lodBuild.TriangleIndices.size());
// copy the index block
uint32 *dst= &lodBuild.TriangleIndices[dstTriIdx];
if(pb.getFormat()==CIndexBuffer::Indices32)
memcpy(dst, iba.getPtr(), pb.getNumIndexes()*sizeof(uint32));
else
{
nlassert(pb.getFormat()==CIndexBuffer::Indices16);
uint16 *src= (uint16*)iba.getPtr();
for(uint n=pb.getNumIndexes();n>0;--n)
*(dst++)=*(src++);
}
// if the material of this pass is the 0th material, flag tris for TextureInfo selection
if(meshMRMGeom.getRdrPassMaterial(0,i)==0)
{
for(uint tri= dstTriIdx/3; tri<dstTriIdx/3+pb.getNumIndexes()/3; tri++)
triangleSelection[tri]= true;
}
// next
dstTriIdx+= pb.getNumIndexes();
}
nlassert(dstTriIdx == lodBuild.TriangleIndices.size());
// build boneNames
lodBuild.BonesNames= meshMRMGeom.getBonesName();
// End: compile texturing information
lodBuild.compile(triangleSelection);
// Ok!!
res= true;
} }
nlassert(dstTriIdx == lodBuild.TriangleIndices.size());
// build boneNames
lodBuild.BonesNames= meshMRMGeom.getBonesName();
// End: compile texturing information
lodBuild.compile(triangleSelection);
// Ok!!
res= true;
} }
}
// Delete the triObject if we should... // Delete the triObject if we should...
if (deleteIt) if (deleteIt)
tri->DeleteMe(); tri->MaybeAutoDelete();
}
} }
} }

View file

@ -1294,6 +1294,7 @@ ITexture* CExportNel::buildATexture (Texmap& texmap, CMaterialDesc &remap3dsTexC
// Ok, good texture // Ok, good texture
pTexture=pTextureCube; pTexture=pTextureCube;
delete srcTex; delete srcTex;
srcTex = NULL;
} }
else else
{ {

View file

@ -68,7 +68,8 @@ CMesh::CMeshBuild* CExportNel::createMeshBuild(INode& node, TimeValue tvTime, CM
baseBuild = new CMeshBase::CMeshBaseBuild(); baseBuild = new CMeshBase::CMeshBaseBuild();
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node.EvalWorldState(tvTime).obj; ObjectState os = node.EvalWorldState(tvTime);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
@ -79,35 +80,39 @@ CMesh::CMeshBuild* CExportNel::createMeshBuild(INode& node, TimeValue tvTime, CM
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0));
if (tri)
{
// Note that the TriObject should only be deleted // Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object // if the pointer to it is not equal to the object
// pointer that called ConvertToType() // pointer that called ConvertToType()
bool deleteIt=false; bool deleteIt=false;
if (obj != tri) if (obj != tri)
deleteIt = true; deleteIt = true;
// Description of materials // Description of materials
CMaxMeshBaseBuild maxBaseBuild; CMaxMeshBaseBuild maxBaseBuild;
// Fill the build interface of CMesh // Fill the build interface of CMesh
// Reset the material array of the buildMesh because it will be rebuild by the exporter // Reset the material array of the buildMesh because it will be rebuild by the exporter
baseBuild->Materials.clear(); baseBuild->Materials.clear();
// Get the node matrix // Get the node matrix
Matrix3 nodeMatrixMax; Matrix3 nodeMatrixMax;
CMatrix nodeMatrix; CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, tvTime); getLocalMatrix (nodeMatrixMax, node, tvTime);
convertMatrix (nodeMatrix, nodeMatrixMax); convertMatrix (nodeMatrix, nodeMatrixMax);
buildBaseMeshInterface (*baseBuild, maxBaseBuild, node, tvTime, nodeMatrix); buildBaseMeshInterface (*baseBuild, maxBaseBuild, node, tvTime, nodeMatrix);
buildMeshInterface (*tri, *pMeshBuild, *baseBuild, maxBaseBuild, node, tvTime, NULL, CMatrix::Identity, masterNodeMat, isMorphTarget); buildMeshInterface (*tri, *pMeshBuild, *baseBuild, maxBaseBuild, node, tvTime, NULL, CMatrix::Identity, masterNodeMat, isMorphTarget);
// Delete the triObject if we should... // Delete the triObject if we should...
if (deleteIt) if (deleteIt)
tri->DeleteMe(); tri->MaybeAutoDelete();
tri = NULL;
}
} }
} }
@ -126,7 +131,7 @@ static void copyMultiLodMeshBaseLod0Infos(CMeshBase::CMeshBaseBuild &dst, const
// *************************************************************************** // ***************************************************************************
// Export a mesh // Export a mesh
IShape* CExportNel::buildShape (INode& node, TimeValue time, const TInodePtrInt *nodeMap, bool buildLods) NLMISC::CSmartPtr<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 ?
@ -134,14 +139,15 @@ IShape* CExportNel::buildShape (INode& node, TimeValue time, const TInodePtrInt
// 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.
IShape *retShape=NULL; CSmartPtr<IShape> retShape = NULL;
// If skinning, disable skin modifier // If skinning, disable skin modifier
if (nodeMap) if (nodeMap)
enableSkinModifier (node, false); enableSkinModifier (node, false);
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node.EvalWorldState(time).obj; ObjectState os = node.EvalWorldState(time);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
@ -184,264 +190,269 @@ IShape* CExportNel::buildShape (INode& node, TimeValue time, const TInodePtrInt
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0));
// Note that the TriObject should only be deleted if (tri)
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt=false;
if (obj != tri)
deleteIt = true;
if (hasWaterMaterial(node, time)) // is this a water shape ?
{ {
retShape = buildWaterShape(node, time); // Note that the TriObject should only be deleted
} // if the pointer to it is not equal to the object
else // pointer that called ConvertToType()
{ bool deleteIt=false;
// Mesh base ? if (obj != tri)
CMeshBase *meshBase; deleteIt = true;
// Get the node matrix if (hasWaterMaterial(node, time)) // is this a water shape ?
Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, time);
convertMatrix (nodeMatrix, nodeMatrixMax);
// Is a multi lod object ?
uint lodCount=getScriptAppData (&node, NEL3D_APPDATA_LOD_NAME_COUNT, 0);
if (lodCount && buildLods)
{ {
// This is a multilod object retShape = buildWaterShape(node, time);
multiLodObject = true; }
else
{
// Mesh base ?
CSmartPtr<CMeshBase> meshBase = NULL;
// Listy of material names // Get the node matrix
std::vector<std::string> listMaterialName; Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, time);
convertMatrix (nodeMatrix, nodeMatrixMax);
// Make the root mesh // Is a multi lod object ?
CMeshMultiLod::CMeshMultiLodBuild multiLodBuild; uint lodCount=getScriptAppData (&node, NEL3D_APPDATA_LOD_NAME_COUNT, 0);
multiLodBuild.LodMeshes.reserve (lodCount+1); if (lodCount && buildLods)
// Resize to one
bool isTransparent;
bool isOpaque;
multiLodBuild.LodMeshes.resize (1);
multiLodBuild.LodMeshes[0].MeshGeom=buildMeshGeom (node, time, nodeMap, multiLodBuild.BaseMesh,
listMaterialName, isTransparent, isOpaque, nodeMatrix);
multiLodBuild.LodMeshes[0].DistMax=getScriptAppData (&node, NEL3D_APPDATA_LOD_DIST_MAX, NEL3D_APPDATA_LOD_DIST_MAX_DEFAULT);
multiLodBuild.LodMeshes[0].BlendLength=getScriptAppData (&node, NEL3D_APPDATA_LOD_BLEND_LENGTH, NEL3D_APPDATA_LOD_BLEND_LENGTH_DEFAULT);
multiLodBuild.LodMeshes[0].Flags=0;
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_BLEND_IN, NEL3D_APPDATA_LOD_BLEND_IN_DEFAULT))
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::BlendIn;
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_BLEND_OUT, NEL3D_APPDATA_LOD_BLEND_OUT_DEFAULT))
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::BlendOut;
if ((getScriptAppData (&node, NEL3D_APPDATA_LOD_COARSE_MESH, NEL3D_APPDATA_LOD_COARSE_MESH_DEFAULT)) && (!_View))
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::CoarseMesh;
if (isTransparent)
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::IsTransparent;
if (isOpaque)
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::IsOpaque;
multiLodBuild.StaticLod=getScriptAppData (&node, NEL3D_APPDATA_LOD_DYNAMIC_MESH, NEL3D_APPDATA_LOD_DYNAMIC_MESH_DEFAULT)==0;
// Bacup scale, rot and pos, etc...
CMeshBase::CMeshBaseBuild bkupMeshBase;
copyMultiLodMeshBaseLod0Infos(bkupMeshBase, multiLodBuild.BaseMesh);
// Build a world to local matrix
CMatrix worldToNodeMatrix;
// Is first slot is skinned ?
INode *rootSkel=getSkeletonRootBone (node);
// For all the other lods
for (uint lod=0; lod<lodCount; lod++)
{ {
// Get the name // This is a multilod object
std::string nodeName=getScriptAppData (&node, NEL3D_APPDATA_LOD_NAME+lod, ""); multiLodObject = true;
// Get the node // Listy of material names
INode *lodNode=_Ip->GetINodeByName(nodeName.c_str()); std::vector<std::string> listMaterialName;
if (lodNode)
// Make the root mesh
CMeshMultiLod::CMeshMultiLodBuild multiLodBuild;
multiLodBuild.LodMeshes.reserve (lodCount+1);
// Resize to one
bool isTransparent;
bool isOpaque;
multiLodBuild.LodMeshes.resize (1);
multiLodBuild.LodMeshes[0].MeshGeom=buildMeshGeom (node, time, nodeMap, multiLodBuild.BaseMesh,
listMaterialName, isTransparent, isOpaque, nodeMatrix);
multiLodBuild.LodMeshes[0].DistMax=getScriptAppData (&node, NEL3D_APPDATA_LOD_DIST_MAX, NEL3D_APPDATA_LOD_DIST_MAX_DEFAULT);
multiLodBuild.LodMeshes[0].BlendLength=getScriptAppData (&node, NEL3D_APPDATA_LOD_BLEND_LENGTH, NEL3D_APPDATA_LOD_BLEND_LENGTH_DEFAULT);
multiLodBuild.LodMeshes[0].Flags=0;
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_BLEND_IN, NEL3D_APPDATA_LOD_BLEND_IN_DEFAULT))
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::BlendIn;
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_BLEND_OUT, NEL3D_APPDATA_LOD_BLEND_OUT_DEFAULT))
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::BlendOut;
if ((getScriptAppData (&node, NEL3D_APPDATA_LOD_COARSE_MESH, NEL3D_APPDATA_LOD_COARSE_MESH_DEFAULT)) && (!_View))
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::CoarseMesh;
if (isTransparent)
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::IsTransparent;
if (isOpaque)
multiLodBuild.LodMeshes[0].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::IsOpaque;
multiLodBuild.StaticLod=getScriptAppData (&node, NEL3D_APPDATA_LOD_DYNAMIC_MESH, NEL3D_APPDATA_LOD_DYNAMIC_MESH_DEFAULT)==0;
// Bacup scale, rot and pos, etc...
CMeshBase::CMeshBaseBuild bkupMeshBase;
copyMultiLodMeshBaseLod0Infos(bkupMeshBase, multiLodBuild.BaseMesh);
// Build a world to local matrix
CMatrix worldToNodeMatrix;
// Is first slot is skinned ?
INode *rootSkel=getSkeletonRootBone (node);
// For all the other lods
for (uint lod=0; lod<lodCount; lod++)
{ {
// Index of the lod in the build structure // Get the name
uint index=multiLodBuild.LodMeshes.size(); std::string nodeName=getScriptAppData (&node, NEL3D_APPDATA_LOD_NAME+lod, "");
// Resize the build structure // Get the node
multiLodBuild.LodMeshes.resize (index+1); INode *lodNode=_Ip->GetINodeByName(nodeName.c_str());
if (lodNode)
// Get matrix node
CMatrix nodeTM;
convertMatrix (nodeTM, lodNode->GetNodeTM (time));
// Get the parent matrix
CMatrix parentMatrix;
if (rootSkel)
{ {
// Yes.. // Index of the lod in the build structure
CMatrix tmp; uint index=multiLodBuild.LodMeshes.size();
convertMatrix (tmp, rootSkel->GetNodeTM (time));
parentMatrix=nodeTM; // Resize the build structure
multiLodBuild.LodMeshes.resize (index+1);
// Get matrix node
CMatrix nodeTM;
convertMatrix (nodeTM, lodNode->GetNodeTM (time));
// Get the parent matrix
CMatrix parentMatrix;
if (rootSkel)
{
// Yes..
CMatrix tmp;
convertMatrix (tmp, rootSkel->GetNodeTM (time));
parentMatrix=nodeTM;
}
else
{
buildNeLMatrix (parentMatrix, bkupMeshBase.DefaultScale, bkupMeshBase.DefaultRotQuat, bkupMeshBase.DefaultPos);
}
// Fill the structure
multiLodBuild.LodMeshes[index].MeshGeom=buildMeshGeom (*lodNode, time, nodeMap, multiLodBuild.BaseMesh,
listMaterialName, isTransparent, isOpaque, parentMatrix);
multiLodBuild.LodMeshes[index].DistMax=getScriptAppData (lodNode, NEL3D_APPDATA_LOD_DIST_MAX, NEL3D_APPDATA_LOD_DIST_MAX_DEFAULT);
multiLodBuild.LodMeshes[index].BlendLength=getScriptAppData (lodNode, NEL3D_APPDATA_LOD_BLEND_LENGTH, NEL3D_APPDATA_LOD_BLEND_LENGTH_DEFAULT);
multiLodBuild.LodMeshes[index].Flags=0;
if (getScriptAppData (lodNode, NEL3D_APPDATA_LOD_BLEND_IN, NEL3D_APPDATA_LOD_BLEND_IN_DEFAULT))
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::BlendIn;
if (getScriptAppData (lodNode, NEL3D_APPDATA_LOD_BLEND_OUT, NEL3D_APPDATA_LOD_BLEND_OUT_DEFAULT))
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::BlendOut;
if ((getScriptAppData (lodNode, NEL3D_APPDATA_LOD_COARSE_MESH, NEL3D_APPDATA_LOD_COARSE_MESH_DEFAULT)) && (!_View))
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::CoarseMesh;
if (isTransparent)
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::IsTransparent;
if (isOpaque)
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::IsOpaque;
}
}
// Restaure default pos, scale and rot, etc...
copyMultiLodMeshBaseLod0Infos(multiLodBuild.BaseMesh, bkupMeshBase);
// Make a CMeshMultiLod mesh object
CMeshMultiLod *multiMesh = new CMeshMultiLod;
++multiMesh->crefs; // hack
// Build it
multiMesh->build(multiLodBuild);
// Return this pointer
meshBase = multiMesh;
// ** force material to be animatable
if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0)
{
/// todo hulud: check if material are animated before
for (uint i=0; i<listMaterialName.size(); i++)
{
meshBase->setAnimatedMaterial (i, listMaterialName[i]);
}
}
}
else
{
// Array of name for the material
CMaxMeshBaseBuild maxBaseBuild;
// Fill the build interface of CMesh
CMeshBase::CMeshBaseBuild buildBaseMesh;
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, nodeMatrix);
CMesh::CMeshBuild buildMesh;
buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, nodeMap);
if( hasLightMap( node, time ) && _Options.bExportLighting )
calculateLM(&buildMesh, &buildBaseMesh, node, time, maxBaseBuild.FirstMaterial, _Options.OutputLightmapLog);
// optimized materials remap
std::vector<sint> materialRemap;
// MRM mesh ?
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_MRM, 0))
{
// Build a MRM parameters block
CMRMParameters parameters;
buildMRMParameters (node, parameters);
// Get the blend shapes that can be linked
std::vector<CMesh::CMeshBuild*> bsList;
getBSMeshBuild (bsList, node, time, nodeMap!=NULL);
// CMeshMRM or CMeshMRMSkinned ?
/*
* Here, export plugin choose between CMeshMRM and CMeshMRMSkinned
*/
if (CMeshMRMSkinned::isCompatible(buildMesh) && bsList.empty())
{
// Make a CMesh object
CMeshMRMSkinned* meshMRMSkinned=new CMeshMRMSkinned;
// Build the mesh with the build interface
meshMRMSkinned->build (buildBaseMesh, buildMesh, parameters);
// optimize number of material
meshMRMSkinned->optimizeMaterialUsage(materialRemap);
// Return this pointer
meshBase=meshMRMSkinned;
} }
else else
{ {
buildNeLMatrix (parentMatrix, bkupMeshBase.DefaultScale, bkupMeshBase.DefaultRotQuat, bkupMeshBase.DefaultPos); // Make a CMesh object
CMeshMRM* meshMRM=new CMeshMRM;
// Build the mesh with the build interface
meshMRM->build (buildBaseMesh, buildMesh, bsList, parameters);
// optimize number of material
meshMRM->optimizeMaterialUsage(materialRemap);
// Return this pointer
meshBase=meshMRM;
} }
// Fill the structure
multiLodBuild.LodMeshes[index].MeshGeom=buildMeshGeom (*lodNode, time, nodeMap, multiLodBuild.BaseMesh,
listMaterialName, isTransparent, isOpaque, parentMatrix);
multiLodBuild.LodMeshes[index].DistMax=getScriptAppData (lodNode, NEL3D_APPDATA_LOD_DIST_MAX, NEL3D_APPDATA_LOD_DIST_MAX_DEFAULT);
multiLodBuild.LodMeshes[index].BlendLength=getScriptAppData (lodNode, NEL3D_APPDATA_LOD_BLEND_LENGTH, NEL3D_APPDATA_LOD_BLEND_LENGTH_DEFAULT);
multiLodBuild.LodMeshes[index].Flags=0;
if (getScriptAppData (lodNode, NEL3D_APPDATA_LOD_BLEND_IN, NEL3D_APPDATA_LOD_BLEND_IN_DEFAULT))
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::BlendIn;
if (getScriptAppData (lodNode, NEL3D_APPDATA_LOD_BLEND_OUT, NEL3D_APPDATA_LOD_BLEND_OUT_DEFAULT))
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::BlendOut;
if ((getScriptAppData (lodNode, NEL3D_APPDATA_LOD_COARSE_MESH, NEL3D_APPDATA_LOD_COARSE_MESH_DEFAULT)) && (!_View))
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::CoarseMesh;
if (isTransparent)
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::IsTransparent;
if (isOpaque)
multiLodBuild.LodMeshes[index].Flags|=CMeshMultiLod::CMeshMultiLodBuild::CBuildSlot::IsOpaque;
}
}
// Restaure default pos, scale and rot, etc...
copyMultiLodMeshBaseLod0Infos(multiLodBuild.BaseMesh, bkupMeshBase);
// Make a CMeshMultiLod mesh object
CMeshMultiLod* multiMesh=new CMeshMultiLod;
// Build it
multiMesh->build (multiLodBuild);
// Return this pointer
meshBase=multiMesh;
// ** force material to be animatable
if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0)
{
/// todo hulud: check if material are animated before
for (uint i=0; i<listMaterialName.size(); i++)
{
meshBase->setAnimatedMaterial (i, listMaterialName[i]);
}
}
}
else
{
// Array of name for the material
CMaxMeshBaseBuild maxBaseBuild;
// Fill the build interface of CMesh
CMeshBase::CMeshBaseBuild buildBaseMesh;
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, nodeMatrix);
CMesh::CMeshBuild buildMesh;
buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, nodeMap);
if( hasLightMap( node, time ) && _Options.bExportLighting )
calculateLM(&buildMesh, &buildBaseMesh, node, time, maxBaseBuild.FirstMaterial, _Options.OutputLightmapLog);
// optimized materials remap
std::vector<sint> materialRemap;
// MRM mesh ?
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_MRM, 0))
{
// Build a MRM parameters block
CMRMParameters parameters;
buildMRMParameters (node, parameters);
// Get the blend shapes that can be linked
std::vector<CMesh::CMeshBuild*> bsList;
getBSMeshBuild (bsList, node, time, nodeMap!=NULL);
// CMeshMRM or CMeshMRMSkinned ?
/*
* Here, export plugin choose between CMeshMRM and CMeshMRMSkinned
*/
if (CMeshMRMSkinned::isCompatible(buildMesh) && bsList.empty())
{
// Make a CMesh object
CMeshMRMSkinned* meshMRMSkinned=new CMeshMRMSkinned;
// Build the mesh with the build interface
meshMRMSkinned->build (buildBaseMesh, buildMesh, parameters);
// optimize number of material
meshMRMSkinned->optimizeMaterialUsage(materialRemap);
// Return this pointer
meshBase=meshMRMSkinned;
} }
else else
{ {
// Make a CMesh object // Make a CMesh object
CMeshMRM* meshMRM=new CMeshMRM; CMesh* mesh=new CMesh;
// Build the mesh with the build interface // Build the mesh with the build interface
meshMRM->build (buildBaseMesh, buildMesh, bsList, parameters); mesh->build (buildBaseMesh, buildMesh);
// Must be done after the build to update vertex links
// Pass to buildMeshMorph if the original mesh is skinned or not
buildMeshMorph (buildMesh, node, time, nodeMap!=NULL);
mesh->setBlendShapes (buildMesh.BlendShapes);
// optimize number of material // optimize number of material
meshMRM->optimizeMaterialUsage(materialRemap); mesh->optimizeMaterialUsage(materialRemap);
// Return this pointer // Return this pointer
meshBase=meshMRM; meshBase=mesh;
}
// Animate materials (must do it after optimizeMaterialUsage());
if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0)
{
for (uint i=0; i<maxBaseBuild.NumMaterials; i++)
{
// get the material name of the original material (not remaped)
std::string matName= maxBaseBuild.MaterialInfo[i].MaterialName;
// get the remaped material id.
sint dstMatId= materialRemap[i];
// if this material still exist in the final data
if(dstMatId>=0)
// animate it
meshBase->setAnimatedMaterial (dstMatId, matName);
}
} }
} }
else
// check wether this mesh is auto-animated. Force to false if in view mode
if ( !_View && (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_AUTOMATIC_ANIMATION, 0) != 0) )
{ {
// Make a CMesh object // yes, it is
CMesh* mesh=new CMesh; meshBase->setAutoAnim(true);
// Build the mesh with the build interface
mesh->build (buildBaseMesh, buildMesh);
// Must be done after the build to update vertex links
// Pass to buildMeshMorph if the original mesh is skinned or not
buildMeshMorph (buildMesh, node, time, nodeMap!=NULL);
mesh->setBlendShapes (buildMesh.BlendShapes);
// optimize number of material
mesh->optimizeMaterialUsage(materialRemap);
// Return this pointer
meshBase=mesh;
} }
// Animate materials (must do it after optimizeMaterialUsage()); // Return the mesh base
if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0) retShape = meshBase;
{
for (uint i=0; i<maxBaseBuild.NumMaterials; i++)
{
// get the material name of the original material (not remaped)
std::string matName= maxBaseBuild.MaterialInfo[i].MaterialName;
// get the remaped material id.
sint dstMatId= materialRemap[i];
// if this material still exist in the final data
if(dstMatId>=0)
// animate it
meshBase->setAnimatedMaterial (dstMatId, matName);
}
}
} }
// check wether this mesh is auto-animated. Force to false if in view mode // Delete the triObject if we should...
if ( !_View && (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_AUTOMATIC_ANIMATION, 0) != 0) ) if (deleteIt)
{ tri->MaybeAutoDelete();
// yes, it is tri = NULL;
meshBase->setAutoAnim(true);
}
// Return the mesh base
retShape=meshBase;
} }
// Delete the triObject if we should...
if (deleteIt)
tri->DeleteMe();
} }
} }
@ -450,7 +461,7 @@ IShape* CExportNel::buildShape (INode& node, TimeValue time, const TInodePtrInt
enableSkinModifier (node, true); enableSkinModifier (node, true);
// Set the dist max for this shape // Set the dist max for this shape
if (retShape && !multiLodObject && buildLods) if (retShape.getPtr() && !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);
@ -1173,6 +1184,7 @@ void CExportNel::getBSMeshBuild (std::vector<CMesh::CMeshBuild*> &bsList, INode
CMeshBase::CMeshBaseBuild *dummyMBB = NULL; CMeshBase::CMeshBaseBuild *dummyMBB = NULL;
std::auto_ptr<CMesh::CMeshBuild> baseMB(createMeshBuild (node, time, dummyMBB, finalSpace)); std::auto_ptr<CMesh::CMeshBuild> baseMB(createMeshBuild (node, time, dummyMBB, finalSpace));
delete dummyMBB; delete dummyMBB;
dummyMBB = NULL;
if (baseMB.get() == NULL) return; if (baseMB.get() == NULL) return;
j = 0; j = 0;
@ -1184,7 +1196,7 @@ void CExportNel::getBSMeshBuild (std::vector<CMesh::CMeshBuild*> &bsList, INode
++j; ++j;
} }
bsList.resize (j); bsList.resize(j, NULL);
j = 0; j = 0;
for (i = 0; i < 100; ++i) for (i = 0; i < 100; ++i)
@ -1198,6 +1210,7 @@ void CExportNel::getBSMeshBuild (std::vector<CMesh::CMeshBuild*> &bsList, INode
// get the meshbuild of the morhp target // get the meshbuild of the morhp target
bsList[j] = createMeshBuild (*pNode, time, pMBB, finalSpace, true); bsList[j] = createMeshBuild (*pNode, time, pMBB, finalSpace, true);
delete pMBB; delete pMBB;
pMBB = NULL;
// copy src normals from src mesh for vertices that are on interfaces // copy src normals from src mesh for vertices that are on interfaces
CMesh::CMeshBuild *mb = bsList[j]; CMesh::CMeshBuild *mb = bsList[j];
if (mb) if (mb)
@ -1281,7 +1294,8 @@ IMeshGeom *CExportNel::buildMeshGeom (INode& node, TimeValue time, const TInodeP
enableSkinModifier (node, false); enableSkinModifier (node, false);
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node.EvalWorldState(time).obj; ObjectState os = node.EvalWorldState(time);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
@ -1291,104 +1305,111 @@ IMeshGeom *CExportNel::buildMeshGeom (INode& node, TimeValue time, const TInodeP
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0));
// Note that the TriObject should only be deleted if (tri)
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt=false;
if (obj != tri)
deleteIt = true;
// Coarse mesh ?
bool coarseMesh=(getScriptAppData (&node, NEL3D_APPDATA_LOD_COARSE_MESH, 0)!=0) && (!_View);
// No skeleton shape
if (coarseMesh)
nodeMap=NULL;
// Array of name for the material
CMaxMeshBaseBuild maxBaseBuild;
// Append material to the base
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, parentMatrix);
// Get the node matrix
Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, time);
convertMatrix (nodeMatrix, nodeMatrixMax);
// Get the node to parent matrix
CMatrix nodeToParentMatrix;
nodeToParentMatrix = parentMatrix.inverted () * nodeMatrix;
// Fill the build interface of CMesh
CMesh::CMeshBuild buildMesh;
buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, nodeMap, nodeToParentMatrix);
// Append material names
isTransparent=false;
isOpaque=false;
for (uint i=0; i<maxBaseBuild.MaterialInfo.size(); i++)
{ {
// Is opaque, transparent ? // Note that the TriObject should only be deleted
if( buildBaseMesh.Materials[i+maxBaseBuild.FirstMaterial].getBlend() ) // if the pointer to it is not equal to the object
isTransparent=true; // pointer that called ConvertToType()
else bool deleteIt = (obj != tri);
isOpaque=true;
// Push the name
listMaterialName.push_back (maxBaseBuild.MaterialInfo[i].MaterialName);
}
if( hasLightMap( node, time ) && _Options.bExportLighting )
calculateLM(&buildMesh, &buildBaseMesh, node, time, maxBaseBuild.FirstMaterial, _Options.OutputLightmapLog);
// MRM mesh ?
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_MRM, 0) && (!coarseMesh) )
{
// Build a MRM parameters block
CMRMParameters parameters;
buildMRMParameters (node, parameters);
// Make a CMesh object
CMeshMRMGeom* meshMRMGeom=new CMeshMRMGeom;
// Get the blend shapes but in mesh build form
std::vector<CMesh::CMeshBuild*> bsList;
getBSMeshBuild (bsList, node, time, nodeMap!=NULL);
// Build the mesh with the build interface
meshMRMGeom->build (buildMesh, bsList, buildBaseMesh.Materials.size(), parameters);
// Return this pointer
meshGeom=meshMRMGeom;
for (uint32 bsListIt = 0; bsListIt < bsList.size(); ++bsListIt)
delete bsList[bsListIt];
}
else
{
// Make a CMesh object
CMeshGeom* mGeom=new CMeshGeom;
// Coarse mesh ? // Coarse mesh ?
bool coarseMesh=(getScriptAppData (&node, NEL3D_APPDATA_LOD_COARSE_MESH, 0)!=0) && (!_View);
// No skeleton shape
if (coarseMesh) if (coarseMesh)
nodeMap=NULL;
// Array of name for the material
CMaxMeshBaseBuild maxBaseBuild;
// Append material to the base
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, parentMatrix);
// Get the node matrix
Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, time);
convertMatrix (nodeMatrix, nodeMatrixMax);
// Get the node to parent matrix
CMatrix nodeToParentMatrix;
nodeToParentMatrix = parentMatrix.inverted () * nodeMatrix;
// Fill the build interface of CMesh
CMesh::CMeshBuild buildMesh;
buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, nodeMap, nodeToParentMatrix);
// Append material names
isTransparent=false;
isOpaque=false;
for (uint i=0; i<maxBaseBuild.MaterialInfo.size(); i++)
{ {
// Force vertex format // Is opaque, transparent ?
buildMesh.VertexFlags=NL3D_COARSEMESH_VERTEX_FORMAT_EXPORT; if( buildBaseMesh.Materials[i+maxBaseBuild.FirstMaterial].getBlend() )
isTransparent=true;
else
isOpaque=true;
// Push the name
listMaterialName.push_back (maxBaseBuild.MaterialInfo[i].MaterialName);
} }
// Build the mesh with the build interface if( hasLightMap( node, time ) && _Options.bExportLighting )
mGeom->build (buildMesh, buildBaseMesh.Materials.size()); calculateLM(&buildMesh, &buildBaseMesh, node, time, maxBaseBuild.FirstMaterial, _Options.OutputLightmapLog);
// Return this pointer // MRM mesh ?
meshGeom=mGeom; if (getScriptAppData (&node, NEL3D_APPDATA_LOD_MRM, 0) && (!coarseMesh) )
{
// Build a MRM parameters block
CMRMParameters parameters;
buildMRMParameters (node, parameters);
// Make a CMesh object
CMeshMRMGeom* meshMRMGeom=new CMeshMRMGeom;
// Get the blend shapes but in mesh build form
std::vector<CMesh::CMeshBuild*> bsList;
getBSMeshBuild (bsList, node, time, nodeMap!=NULL);
// Build the mesh with the build interface
meshMRMGeom->build (buildMesh, bsList, buildBaseMesh.Materials.size(), parameters);
// Return this pointer
meshGeom=meshMRMGeom;
#ifdef NL_DONT_FIND_MAX_CRASH
for (uint32 bsListIt = 0; bsListIt < bsList.size(); ++bsListIt)
{
delete bsList[bsListIt];
bsList[bsListIt] = NULL;
}
#endif
}
else
{
// Make a CMesh object
CMeshGeom* mGeom=new CMeshGeom;
// Coarse mesh ?
if (coarseMesh)
{
// Force vertex format
buildMesh.VertexFlags=NL3D_COARSEMESH_VERTEX_FORMAT_EXPORT;
}
// Build the mesh with the build interface
mGeom->build(buildMesh, buildBaseMesh.Materials.size());
// Return this pointer
meshGeom=mGeom;
}
// Delete the triObject if we should...
if (deleteIt)
tri->MaybeAutoDelete();
tri = NULL;
} }
// Delete the triObject if we should...
if (deleteIt)
tri->DeleteMe();
} }
} }
@ -1397,7 +1418,7 @@ IMeshGeom *CExportNel::buildMeshGeom (INode& node, TimeValue time, const TInodeP
enableSkinModifier (node, true); enableSkinModifier (node, true);
if (InfoLog) if (InfoLog)
InfoLog->display("buidlMeshGeom : %d ms\n", timeGetTime()-t); InfoLog->display("buildMeshGeom : %d ms\n", timeGetTime()-t);
if (InfoLog) if (InfoLog)
InfoLog->display("End of %s \n", node.GetName()); InfoLog->display("End of %s \n", node.GetName());
@ -1657,10 +1678,15 @@ NL3D::IShape *CExportNel::buildWaterShape(INode& node, TimeValue time)
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node.EvalWorldState(time).obj; ObjectState os = node.EvalWorldState(time);
Object *obj = os.obj;
if (!obj) return NULL;
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject *) obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0));
if (!tri) return NULL;
// Note that the TriObject should only be deleted // Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object // if the pointer to it is not equal to the object
@ -2033,7 +2059,8 @@ NL3D::IShape *CExportNel::buildWaterShape(INode& node, TimeValue time)
// Delete the triObject if we should... // Delete the triObject if we should...
if (deleteIt) if (deleteIt)
tri->DeleteMe(); tri->MaybeAutoDelete();
tri = NULL;
nlinfo("WaterShape : build succesful"); nlinfo("WaterShape : build succesful");
return ws; return ws;
} }
@ -2047,11 +2074,13 @@ NL3D::IShape *CExportNel::buildWaterShape(INode& node, TimeValue time)
// *************************************************************************** // ***************************************************************************
bool CExportNel::buildMeshAABBox(INode &node, NLMISC::CAABBox &dest, TimeValue time) bool CExportNel::buildMeshAABBox(INode &node, NLMISC::CAABBox &dest, TimeValue time)
{ {
Object *obj = node.EvalWorldState(time).obj; ObjectState os = node.EvalWorldState(time);
Object *obj = os.obj;
if (!obj) return false; if (!obj) return false;
if (!obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) return false; if (!obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) return false;
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject*)obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject*)obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0));
if (!tri) return false;
// Note that the TriObject should only be deleted // Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object // if the pointer to it is not equal to the object
// pointer that called ConvertToType() // pointer that called ConvertToType()
@ -2073,10 +2102,11 @@ bool CExportNel::buildMeshAABBox(INode &node, NLMISC::CAABBox &dest, TimeValue t
// //
if (deleteIt) if (deleteIt)
{ {
#ifndef NL_DEBUG #ifdef NL_DONT_FIND_MAX_CRASH
tri->DeleteMe(); tri->MaybeAutoDelete();
#endif // NL_DEBUG #endif // NL_DEBUG
} }
tri = NULL;
return true; return true;
} }

View file

@ -131,7 +131,8 @@ struct CMeshInterface
bool CMeshInterface::buildFromMaxMesh(INode &node, TimeValue tvTime) bool CMeshInterface::buildFromMaxMesh(INode &node, TimeValue tvTime)
{ {
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node.EvalWorldState(tvTime).obj; ObjectState os = node.EvalWorldState(tvTime);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (!obj) return false; if (!obj) return false;
@ -140,6 +141,8 @@ bool CMeshInterface::buildFromMaxMesh(INode &node, TimeValue tvTime)
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0));
if (!tri) return false;
// Note that the TriObject should only be deleted // Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object // if the pointer to it is not equal to the object
@ -177,9 +180,8 @@ bool CMeshInterface::buildFromMaxMesh(INode &node, TimeValue tvTime)
} }
// //
if (deleteIt) if (deleteIt)
{ tri->MaybeAutoDelete();
tri->DeleteMe(); tri = NULL;
}
return true; return true;
} }
return false; return false;
@ -316,50 +318,53 @@ static void AddNodeToQuadGrid(const NLMISC::CAABBox &delimiter, TNodeFaceQG &des
{ {
nldebug((std::string("Adding ") + node.GetName() + std::string(" to mesh interface quad grid")).c_str()); nldebug((std::string("Adding ") + node.GetName() + std::string(" to mesh interface quad grid")).c_str());
// add this node tris // add this node tris
Object *obj = node.EvalWorldState(time).obj; ObjectState os = node.EvalWorldState(time);
Object *obj = os.obj;
if (obj) if (obj)
{ {
if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)))
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject*)obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject*)obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0));
// Note that the TriObject should only be deleted if (tri)
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt = false;
if (obj != tri)
deleteIt = true;
Mesh &mesh = tri->GetMesh();
Matrix3 nodeMat = node.GetObjectTM(time);
CNodeFace nodeFace;
NLMISC::CAABBox faceBBox;
uint numFaceAdded = 0;
for(sint l = 0; l < mesh.getNumFaces(); ++l)
{ {
for(uint m = 0; m < 3; ++m) // Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt = false;
if (obj != tri)
deleteIt = true;
Mesh &mesh = tri->GetMesh();
Matrix3 nodeMat = node.GetObjectTM(time);
CNodeFace nodeFace;
NLMISC::CAABBox faceBBox;
uint numFaceAdded = 0;
for(sint l = 0; l < mesh.getNumFaces(); ++l)
{ {
Point3 pos = nodeMat * mesh.getVert(mesh.faces[l].v[m]); for(uint m = 0; m < 3; ++m)
CExportNel::convertVector(nodeFace.P[m], pos); {
} Point3 pos = nodeMat * mesh.getVert(mesh.faces[l].v[m]);
// test if we must insert in quadgrid CExportNel::convertVector(nodeFace.P[m], pos);
nodeFace.buildBBox(faceBBox); }
if (faceBBox.intersect(delimiter)) // test if we must insert in quadgrid
{ nodeFace.buildBBox(faceBBox);
nodeFace.SmoothGroup = mesh.faces[l].smGroup; if (faceBBox.intersect(delimiter))
destQuadGrid.insert(faceBBox.getMin(), faceBBox.getMax(), nodeFace); {
++ numFaceAdded; nodeFace.SmoothGroup = mesh.faces[l].smGroup;
} destQuadGrid.insert(faceBBox.getMin(), faceBBox.getMax(), nodeFace);
++ numFaceAdded;
} }
nldebug("%d faces where added", numFaceAdded);
// }
if (deleteIt) nldebug("%d faces where added", numFaceAdded);
{ //
tri->DeleteMe(); if (deleteIt)
} tri->MaybeAutoDelete();
tri = NULL;
}
} }
} }
} }
@ -478,16 +483,20 @@ static void ApplyMeshInterfacesUsingSceneNormals(INode &sceneBaseNode, std::vect
*/ */
static bool SelectVerticesInMeshFromInterfaces(const std::vector<CMeshInterface> &inters, float threshold, INode &node, TimeValue tvTime) static bool SelectVerticesInMeshFromInterfaces(const std::vector<CMeshInterface> &inters, float threshold, INode &node, TimeValue tvTime)
{ {
Object *obj = node.EvalWorldState(tvTime).obj; ObjectState os = node.EvalWorldState(tvTime);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (!obj) return false;
if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)))
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0));
if (!tri) return false;
if (obj != tri) if (obj != tri)
{ {
// not a mesh object, so do nothing // not a mesh object, so do nothing
tri->DeleteMe(); tri->MaybeAutoDelete();
tri = NULL;
return false; return false;
} }

View file

@ -511,7 +511,8 @@ std::string CExportNel::getNelObjectName (INode& node)
{ {
// Workaround for FX (don't know why, but the AppData are not copied when FX are duplicated, so try to get the name in another way) // Workaround for FX (don't know why, but the AppData are not copied when FX are duplicated, so try to get the name in another way)
// If this is a particle system, try to get the name of the shape.from the param blocks // If this is a particle system, try to get the name of the shape.from the param blocks
Object *obj = node.EvalWorldState(0).obj; ObjectState os = node.EvalWorldState(0);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
{ {
@ -542,7 +543,8 @@ std::string CExportNel::getNelObjectName (INode& node)
} }
else else
{ {
Object *obj = node.EvalWorldState(0).obj; ObjectState os = node.EvalWorldState(0);
Object *obj = os.obj;
if (obj) if (obj)
{ {
ad = obj->GetAppDataChunk (MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, NEL3D_APPDATA_INSTANCE_SHAPE); ad = obj->GetAppDataChunk (MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, NEL3D_APPDATA_INSTANCE_SHAPE);
@ -906,7 +908,8 @@ void CExportNel::getObjectNodes (std::vector<INode*>& vectNode, TimeValue time,
node=_Ip->GetRootNode(); node=_Ip->GetRootNode();
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node->EvalWorldState(time).obj; ObjectState os = node->EvalWorldState(time);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
@ -1257,7 +1260,8 @@ void CExportNel::buildCamera(NL3D::CCameraInfo &cameraInfo, INode& node, TimeVal
cameraInfo.Fov = genCamera->GetFOV(time); cameraInfo.Fov = genCamera->GetFOV(time);
if (deleteIt) if (deleteIt)
genCamera->DeleteMe(); genCamera->MaybeAutoDelete();
genCamera = NULL;
} }
} }
} }

View file

@ -292,7 +292,7 @@ public:
* *
* skeletonShape must be NULL if no bones. * skeletonShape must be NULL if no bones.
*/ */
NL3D::IShape* buildShape (INode& node, TimeValue time, const TInodePtrInt *nodeMap, NLMISC::CSmartPtr<NL3D::IShape> buildShape (INode& node, TimeValue time, const TInodePtrInt *nodeMap,
bool buildLods); bool buildLods);
/** /**

View file

@ -26,7 +26,8 @@ using namespace NL3D;
IShape* CExportNel::buildParticleSystem(INode& node, TimeValue time) IShape* CExportNel::buildParticleSystem(INode& node, TimeValue time)
{ {
Object *obj = node.EvalWorldState(time).obj; ObjectState os = node.EvalWorldState(time);
Object *obj = os.obj;
nlassert(obj); nlassert(obj);
std::string shapeName; std::string shapeName;
// try to get the complete path // try to get the complete path

View file

@ -249,8 +249,8 @@ CInstanceGroup* CExportNel::buildInstanceGroup(const vector<INode*>& vectNode, v
clusterTemp.Name = pNode->GetName(); clusterTemp.Name = pNode->GetName();
vClusters.push_back (clusterTemp); vClusters.push_back (clusterTemp);
delete pMB; delete pMB; pMB = NULL;
delete pMBB; delete pMBB; pMBB = NULL;
} }
} }
@ -376,7 +376,9 @@ CInstanceGroup* CExportNel::buildInstanceGroup(const vector<INode*>& vectNode, v
vPortals.push_back (portalTemp); vPortals.push_back (portalTemp);
delete pMB; delete pMB;
pMB = NULL;
delete pMBB; delete pMBB;
pMBB = NULL;
} }
} }
@ -406,7 +408,8 @@ CInstanceGroup* CExportNel::buildInstanceGroup(const vector<INode*>& vectNode, v
* If it is a FX, we read its bbox from its shape * If it is a FX, we read its bbox from its shape
* If we can't read it, we use the bbox of the fx helper in max * If we can't read it, we use the bbox of the fx helper in max
*/ */
Object *obj = pNode->EvalWorldState(tvTime).obj; ObjectState os = pNode->EvalWorldState(tvTime);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
{ {
@ -452,6 +455,7 @@ CInstanceGroup* CExportNel::buildInstanceGroup(const vector<INode*>& vectNode, v
buildMeshBBox = false; buildMeshBBox = false;
} }
delete ss.getShapePointer(); delete ss.getShapePointer();
ss.setShapePointer(NULL);
} }
catch (NLMISC::Exception &e) catch (NLMISC::Exception &e)
{ {
@ -506,8 +510,8 @@ CInstanceGroup* CExportNel::buildInstanceGroup(const vector<INode*>& vectNode, v
} }
// debug purpose : to remove // debug purpose : to remove
delete pMB; delete pMB; pMB = NULL;
delete pMBB; delete pMBB; pMBB = NULL;
} }
++nNumIG; ++nNumIG;
@ -911,7 +915,7 @@ void CExportNel::buildScene (NL3D::CScene &scene, NL3D::CShapeBank &shapeBank, I
// Swap pointer and release unlighted one. // Swap pointer and release unlighted one.
swap(ig, igOut); swap(ig, igOut);
delete igOut; delete igOut; igOut = NULL;
} }
// Add all models to the scene // Add all models to the scene

View file

@ -1386,7 +1386,8 @@ bool CExportNel::mirrorPhysiqueSelection(INode &node, TimeValue tvTime, const st
uint vertCount; uint vertCount;
// Get a pointer on the object's node. // Get a pointer on the object's node.
Object *obj = node.EvalWorldState(tvTime).obj; ObjectState os = node.EvalWorldState(tvTime);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
ok= false; ok= false;
@ -1398,35 +1399,39 @@ bool CExportNel::mirrorPhysiqueSelection(INode &node, TimeValue tvTime, const st
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject*)obj->ConvertToType(tvTime, Class_ID(TRIOBJ_CLASS_ID, 0));
// Note that the TriObject should only be deleted if (tri)
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt=false;
if (obj != tri)
deleteIt = true;
// Get the node matrix. TODO: Matrix headhache?
/*Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, tvTime);
convertMatrix (nodeMatrix, nodeMatrixMax);*/
// retrive Position geometry
vertCount= tri->NumPoints();
tempVertex.resize(vertCount);
for(uint i=0;i<vertCount;i++)
{ {
Point3 v= tri->GetPoint(i); // Note that the TriObject should only be deleted
tempVertex[i].Pos.set(v.x, v.y, v.z); // if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt=false;
if (obj != tri)
deleteIt = true;
// Get the node matrix. TODO: Matrix headhache?
/*Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, tvTime);
convertMatrix (nodeMatrix, nodeMatrixMax);*/
// retrive Position geometry
vertCount= tri->NumPoints();
tempVertex.resize(vertCount);
for(uint i=0;i<vertCount;i++)
{
Point3 v= tri->GetPoint(i);
tempVertex[i].Pos.set(v.x, v.y, v.z);
}
// Delete the triObject if we should...
if (deleteIt)
tri->MaybeAutoDelete();
tri = NULL;
// ok!
ok= true;
} }
// Delete the triObject if we should...
if (deleteIt)
tri->DeleteMe();
// ok!
ok= true;
} }
} }
if(!ok) if(!ok)

View file

@ -33,7 +33,8 @@ bool CExportNel::buildVegetableShape (NL3D::CVegetableShape& skeletonShape, INo
bool res = false; bool res = false;
// Get a pointer on the object's node // Get a pointer on the object's node
Object *obj = node.EvalWorldState(time).obj; ObjectState os = node.EvalWorldState(time);
Object *obj = os.obj;
// Check if there is an object // Check if there is an object
if (obj) if (obj)
@ -42,116 +43,119 @@ bool CExportNel::buildVegetableShape (NL3D::CVegetableShape& skeletonShape, INo
{ {
// Get a triobject from the node // Get a triobject from the node
TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0)); TriObject *tri = (TriObject *) obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0));
// Note that the TriObject should only be deleted if (tri)
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt=false;
if (obj != tri)
deleteIt = true;
// Build a mesh base structure
CMeshBase::CMeshBaseBuild buildBaseMesh;
CMaxMeshBaseBuild maxBaseBuild;
// Get the node matrix
Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, time);
convertMatrix (nodeMatrix, nodeMatrixMax);
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, nodeMatrix);
// Build a mesh
CMesh::CMeshBuild buildMesh;
buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, NULL);
// Has UV 1
if ((buildMesh.VertexFlags & CVertexBuffer::TexCoord0Flag) == 0)
{
// Error
outputErrorMessage ("Can't build vegetable mesh: need UV1 coordinates");
}
else
{ {
// Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
bool deleteIt=false;
if (obj != tri)
deleteIt = true;
// Build a mesh base structure
CMeshBase::CMeshBaseBuild buildBaseMesh;
CMaxMeshBaseBuild maxBaseBuild;
// Get the node matrix
Matrix3 nodeMatrixMax;
CMatrix nodeMatrix;
getLocalMatrix (nodeMatrixMax, node, time);
convertMatrix (nodeMatrix, nodeMatrixMax);
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, nodeMatrix);
// Build a mesh // Build a mesh
CMesh mesh; CMesh::CMeshBuild buildMesh;
mesh.build (buildBaseMesh, buildMesh); buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, NULL);
// Number of matrix block // Has UV 1
if (mesh.getNbMatrixBlock () != 1) if ((buildMesh.VertexFlags & CVertexBuffer::TexCoord0Flag) == 0)
{ {
// Error // Error
outputErrorMessage ("The object can't be skinned"); outputErrorMessage ("Can't build vegetable mesh: need UV1 coordinates");
} }
else else
{ {
// Number of render pass // Build a mesh
if (mesh.getNbRdrPass (0) != 1) CMesh mesh;
mesh.build (buildBaseMesh, buildMesh);
// Number of matrix block
if (mesh.getNbMatrixBlock () != 1)
{ {
// Error // Error
outputErrorMessage ("The object must have less than one material!"); outputErrorMessage ("The object can't be skinned");
} }
else else
{ {
// Build a vegetable mesh // Number of render pass
CVegetableShapeBuild vegetableBuild; if (mesh.getNbRdrPass (0) != 1)
// Copy the vertex buffer
vegetableBuild.VB = mesh.getVertexBuffer ();
// Copy the primitive block
vegetableBuild.PB = mesh.getRdrPassPrimitiveBlock (0, 0);
// Get the appdata
vegetableBuild.AlphaBlend = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND, 0) == 0;
// Alpha blend ?
if (vegetableBuild.AlphaBlend)
{ {
// Default options // Error
vegetableBuild.PreComputeLighting = true; outputErrorMessage ("The object must have less than one material!");
vegetableBuild.DoubleSided = true;
// Lighted ?
vegetableBuild.Lighted = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND_ON_LIGHTED, 0) == 0;
} }
else else
{ {
// Lighted ? // Build a vegetable mesh
vegetableBuild.Lighted = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND_OFF_LIGHTED, 0) != 2; CVegetableShapeBuild vegetableBuild;
// Precompute light ? // Copy the vertex buffer
vegetableBuild.PreComputeLighting = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND_OFF_LIGHTED, 0) == 0; vegetableBuild.VB = mesh.getVertexBuffer ();
// Double sided ? // Copy the primitive block
vegetableBuild.DoubleSided = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND_OFF_DOUBLE_SIDED, 0) != BST_UNCHECKED; vegetableBuild.PB = mesh.getRdrPassPrimitiveBlock (0, 0);
// Get the appdata
vegetableBuild.AlphaBlend = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND, 0) == 0;
// Alpha blend ?
if (vegetableBuild.AlphaBlend)
{
// Default options
vegetableBuild.PreComputeLighting = true;
vegetableBuild.DoubleSided = true;
// Lighted ?
vegetableBuild.Lighted = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND_ON_LIGHTED, 0) == 0;
}
else
{
// Lighted ?
vegetableBuild.Lighted = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND_OFF_LIGHTED, 0) != 2;
// Precompute light ?
vegetableBuild.PreComputeLighting = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND_OFF_LIGHTED, 0) == 0;
// Double sided ?
vegetableBuild.DoubleSided = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_ALPHA_BLEND_OFF_DOUBLE_SIDED, 0) != BST_UNCHECKED;
}
// PreComputeLighting?
if (vegetableBuild.PreComputeLighting)
{
// BestSidedPreComputeLighting?
vegetableBuild.BestSidedPreComputeLighting= CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_FORCE_BEST_SIDED_LIGHTING, 0) != BST_UNCHECKED;
}
// Max bend weight
vegetableBuild.MaxBendWeight = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_BEND_FACTOR, NEL3D_APPDATA_BEND_FACTOR_DEFAULT);
// BendMode
vegetableBuild.BendCenterMode = (CVegetableShapeBuild::TBendCenterMode)CExportNel::getScriptAppData (&node, NEL3D_APPDATA_BEND_CENTER, 0);
// Build it
skeletonShape.build (vegetableBuild);
// Ok
res = true;
} }
// PreComputeLighting?
if (vegetableBuild.PreComputeLighting)
{
// BestSidedPreComputeLighting?
vegetableBuild.BestSidedPreComputeLighting= CExportNel::getScriptAppData (&node, NEL3D_APPDATA_VEGETABLE_FORCE_BEST_SIDED_LIGHTING, 0) != BST_UNCHECKED;
}
// Max bend weight
vegetableBuild.MaxBendWeight = CExportNel::getScriptAppData (&node, NEL3D_APPDATA_BEND_FACTOR, NEL3D_APPDATA_BEND_FACTOR_DEFAULT);
// BendMode
vegetableBuild.BendCenterMode = (CVegetableShapeBuild::TBendCenterMode)CExportNel::getScriptAppData (&node, NEL3D_APPDATA_BEND_CENTER, 0);
// Build it
skeletonShape.build (vegetableBuild);
// Ok
res = true;
} }
} }
}
if (deleteIt) if (deleteIt)
tri->DeleteMe(); tri->MaybeAutoDelete();
}
} }
} }

View file

@ -101,3 +101,8 @@ for m in getClassInstances NelMaterial do
m.delegate.ReflectionMap = undefined m.delegate.ReflectionMap = undefined
m.delegate.RefractionMap = undefined m.delegate.RefractionMap = undefined
) )
actionMan.executeAction 0 "40021" -- Selection: Select All
actionMan.executeAction 0 "311" -- Tools: Zoom Extents All Selected
actionMan.executeAction 0 "63508" -- Views: Standard Display with Maps
actionMan.executeAction 0 "40043" -- Selection: Select None

View file

@ -169,9 +169,12 @@ rollout assets_png_rollout "Properties"
m.delegate.ReflectionMap = undefined m.delegate.ReflectionMap = undefined
m.delegate.RefractionMap = undefined m.delegate.RefractionMap = undefined
) )
actionMan.executeAction 0 "63508" -- Views: Standard Display with Maps
actionMan.executeAction 0 "40021" -- Selection: Select All actionMan.executeAction 0 "40021" -- Selection: Select All
actionMan.executeAction 0 "311" -- Tools: Zoom Extents All Selected actionMan.executeAction 0 "311" -- Tools: Zoom Extents All Selected
actionMan.executeAction 0 "63508" -- Views: Standard Display with Maps
actionMan.executeAction 0 "40043" -- Selection: Select None
return 1 return 1
) )

View file

@ -141,3 +141,8 @@ for m in getClassInstances NelMaterial do
m.delegate.ReflectionMap = undefined m.delegate.ReflectionMap = undefined
m.delegate.RefractionMap = undefined m.delegate.RefractionMap = undefined
) )
actionMan.executeAction 0 "40021" -- Selection: Select All
actionMan.executeAction 0 "311" -- Tools: Zoom Extents All Selected
actionMan.executeAction 0 "63508" -- Views: Standard Display with Maps
actionMan.executeAction 0 "40043" -- Selection: Select None