|
|
@ -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
|
|
|
|
// Listy of material names
|
|
|
|
{
|
|
|
|
std::vector<std::string> listMaterialName;
|
|
|
|
// Mesh base ?
|
|
|
|
|
|
|
|
CSmartPtr<CMeshBase> meshBase = NULL;
|
|
|
|
// Make the root mesh
|
|
|
|
|
|
|
|
CMeshMultiLod::CMeshMultiLodBuild multiLodBuild;
|
|
|
|
// Get the node matrix
|
|
|
|
multiLodBuild.LodMeshes.reserve (lodCount+1);
|
|
|
|
Matrix3 nodeMatrixMax;
|
|
|
|
|
|
|
|
CMatrix nodeMatrix;
|
|
|
|
// Resize to one
|
|
|
|
getLocalMatrix (nodeMatrixMax, node, time);
|
|
|
|
bool isTransparent;
|
|
|
|
convertMatrix (nodeMatrix, nodeMatrixMax);
|
|
|
|
bool isOpaque;
|
|
|
|
|
|
|
|
multiLodBuild.LodMeshes.resize (1);
|
|
|
|
// Is a multi lod object ?
|
|
|
|
multiLodBuild.LodMeshes[0].MeshGeom=buildMeshGeom (node, time, nodeMap, multiLodBuild.BaseMesh,
|
|
|
|
uint lodCount=getScriptAppData (&node, NEL3D_APPDATA_LOD_NAME_COUNT, 0);
|
|
|
|
listMaterialName, isTransparent, isOpaque, nodeMatrix);
|
|
|
|
if (lodCount && buildLods)
|
|
|
|
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..
|
|
|
|
|
|
|
|
CMatrix tmp;
|
|
|
|
|
|
|
|
convertMatrix (tmp, rootSkel->GetNodeTM (time));
|
|
|
|
|
|
|
|
parentMatrix=nodeTM;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
buildNeLMatrix (parentMatrix, bkupMeshBase.DefaultScale, bkupMeshBase.DefaultRotQuat, bkupMeshBase.DefaultPos);
|
|
|
|
// Index of the lod in the build structure
|
|
|
|
|
|
|
|
uint index=multiLodBuild.LodMeshes.size();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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...
|
|
|
|
// Restaure default pos, scale and rot, etc...
|
|
|
|
copyMultiLodMeshBaseLod0Infos(multiLodBuild.BaseMesh, bkupMeshBase);
|
|
|
|
copyMultiLodMeshBaseLod0Infos(multiLodBuild.BaseMesh, bkupMeshBase);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make a CMeshMultiLod mesh object
|
|
|
|
// Make a CMeshMultiLod mesh object
|
|
|
|
CMeshMultiLod* multiMesh=new CMeshMultiLod;
|
|
|
|
CMeshMultiLod *multiMesh = new CMeshMultiLod;
|
|
|
|
|
|
|
|
++multiMesh->crefs; // hack
|
|
|
|
|
|
|
|
|
|
|
|
// Build it
|
|
|
|
// Build it
|
|
|
|
multiMesh->build (multiLodBuild);
|
|
|
|
multiMesh->build(multiLodBuild);
|
|
|
|
|
|
|
|
|
|
|
|
// Return this pointer
|
|
|
|
// Return this pointer
|
|
|
|
meshBase=multiMesh;
|
|
|
|
meshBase = multiMesh;
|
|
|
|
|
|
|
|
|
|
|
|
// ** force material to be animatable
|
|
|
|
// ** force material to be animatable
|
|
|
|
if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0)
|
|
|
|
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]);
|
|
|
|
/// todo hulud: check if material are animated before
|
|
|
|
|
|
|
|
for (uint i=0; i<listMaterialName.size(); i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
meshBase->setAnimatedMaterial (i, listMaterialName[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
|
|
if( hasLightMap( node, time ) && _Options.bExportLighting )
|
|
|
|
if( hasLightMap( node, time ) && _Options.bExportLighting )
|
|
|
|
calculateLM(&buildMesh, &buildBaseMesh, node, time, maxBaseBuild.FirstMaterial, _Options.OutputLightmapLog);
|
|
|
|
calculateLM(&buildMesh, &buildBaseMesh, node, time, maxBaseBuild.FirstMaterial, _Options.OutputLightmapLog);
|
|
|
|
|
|
|
|
|
|
|
|
// optimized materials remap
|
|
|
|
// optimized materials remap
|
|
|
|
std::vector<sint> materialRemap;
|
|
|
|
std::vector<sint> materialRemap;
|
|
|
|
|
|
|
|
|
|
|
|
// MRM mesh ?
|
|
|
|
// MRM mesh ?
|
|
|
|
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_MRM, 0))
|
|
|
|
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_MRM, 0))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Build a MRM parameters block
|
|
|
|
// Build a MRM parameters block
|
|
|
|
CMRMParameters parameters;
|
|
|
|
CMRMParameters parameters;
|
|
|
|
buildMRMParameters (node, parameters);
|
|
|
|
buildMRMParameters (node, parameters);
|
|
|
|
|
|
|
|
|
|
|
|
// Get the blend shapes that can be linked
|
|
|
|
// Get the blend shapes that can be linked
|
|
|
|
std::vector<CMesh::CMeshBuild*> bsList;
|
|
|
|
std::vector<CMesh::CMeshBuild*> bsList;
|
|
|
|
getBSMeshBuild (bsList, node, time, nodeMap!=NULL);
|
|
|
|
getBSMeshBuild (bsList, node, time, nodeMap!=NULL);
|
|
|
|
|
|
|
|
|
|
|
|
// CMeshMRM or CMeshMRMSkinned ?
|
|
|
|
// CMeshMRM or CMeshMRMSkinned ?
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Here, export plugin choose between CMeshMRM and CMeshMRMSkinned
|
|
|
|
* Here, export plugin choose between CMeshMRM and CMeshMRMSkinned
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
if (CMeshMRMSkinned::isCompatible(buildMesh) && bsList.empty())
|
|
|
|
if (CMeshMRMSkinned::isCompatible(buildMesh) && bsList.empty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Make a CMesh object
|
|
|
|
// Make a CMesh object
|
|
|
|
CMeshMRMSkinned* meshMRMSkinned=new CMeshMRMSkinned;
|
|
|
|
CMeshMRMSkinned* meshMRMSkinned=new CMeshMRMSkinned;
|
|
|
|
|
|
|
|
|
|
|
|
// Build the mesh with the build interface
|
|
|
|
// Build the mesh with the build interface
|
|
|
|
meshMRMSkinned->build (buildBaseMesh, buildMesh, parameters);
|
|
|
|
meshMRMSkinned->build (buildBaseMesh, buildMesh, parameters);
|
|
|
|
|
|
|
|
|
|
|
|
// optimize number of material
|
|
|
|
// optimize number of material
|
|
|
|
meshMRMSkinned->optimizeMaterialUsage(materialRemap);
|
|
|
|
meshMRMSkinned->optimizeMaterialUsage(materialRemap);
|
|
|
|
|
|
|
|
|
|
|
|
// Return this pointer
|
|
|
|
// Return this pointer
|
|
|
|
meshBase=meshMRMSkinned;
|
|
|
|
meshBase=meshMRMSkinned;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Make a CMesh object
|
|
|
|
|
|
|
|
CMesh* mesh=new CMesh;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Build the mesh with the build interface
|
|
|
|
|
|
|
|
mesh->build (buildBaseMesh, buildMesh);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Must be done after the build to update vertex links
|
|
|
|
// Animate materials (must do it after optimizeMaterialUsage());
|
|
|
|
// Pass to buildMeshMorph if the original mesh is skinned or not
|
|
|
|
if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0)
|
|
|
|
buildMeshMorph (buildMesh, node, time, nodeMap!=NULL);
|
|
|
|
{
|
|
|
|
mesh->setBlendShapes (buildMesh.BlendShapes);
|
|
|
|
for (uint i=0; i<maxBaseBuild.NumMaterials; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
// optimize number of material
|
|
|
|
// get the material name of the original material (not remaped)
|
|
|
|
mesh->optimizeMaterialUsage(materialRemap);
|
|
|
|
std::string matName= maxBaseBuild.MaterialInfo[i].MaterialName;
|
|
|
|
|
|
|
|
// get the remaped material id.
|
|
|
|
// Return this pointer
|
|
|
|
sint dstMatId= materialRemap[i];
|
|
|
|
meshBase=mesh;
|
|
|
|
|
|
|
|
|
|
|
|
// if this material still exist in the final data
|
|
|
|
|
|
|
|
if(dstMatId>=0)
|
|
|
|
|
|
|
|
// animate it
|
|
|
|
|
|
|
|
meshBase->setAnimatedMaterial (dstMatId, matName);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Animate materials (must do it after optimizeMaterialUsage());
|
|
|
|
// check wether this mesh is auto-animated. Force to false if in view mode
|
|
|
|
if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0)
|
|
|
|
if ( !_View && (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_AUTOMATIC_ANIMATION, 0) != 0) )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
for (uint i=0; i<maxBaseBuild.NumMaterials; i++)
|
|
|
|
// yes, it is
|
|
|
|
{
|
|
|
|
meshBase->setAutoAnim(true);
|
|
|
|
// 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
|
|
|
|
// Return the mesh base
|
|
|
|
if ( !_View && (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_AUTOMATIC_ANIMATION, 0) != 0) )
|
|
|
|
retShape = meshBase;
|
|
|
|
{
|
|
|
|
|
|
|
|
// yes, it is
|
|
|
|
|
|
|
|
meshBase->setAutoAnim(true);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return the mesh base
|
|
|
|
// Delete the triObject if we should...
|
|
|
|
retShape=meshBase;
|
|
|
|
if (deleteIt)
|
|
|
|
|
|
|
|
tri->MaybeAutoDelete();
|
|
|
|
|
|
|
|
tri = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
@ -1292,103 +1306,110 @@ 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()
|
|
|
|
// Note that the TriObject should only be deleted
|
|
|
|
bool deleteIt=false;
|
|
|
|
// if the pointer to it is not equal to the object
|
|
|
|
if (obj != tri)
|
|
|
|
// pointer that called ConvertToType()
|
|
|
|
deleteIt = true;
|
|
|
|
bool deleteIt = (obj != tri);
|
|
|
|
|
|
|
|
|
|
|
|
// Coarse mesh ?
|
|
|
|
|
|
|
|
bool coarseMesh=(getScriptAppData (&node, NEL3D_APPDATA_LOD_COARSE_MESH, 0)!=0) && (!_View);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// No skeleton shape
|
|
|
|
// Coarse mesh ?
|
|
|
|
if (coarseMesh)
|
|
|
|
bool coarseMesh=(getScriptAppData (&node, NEL3D_APPDATA_LOD_COARSE_MESH, 0)!=0) && (!_View);
|
|
|
|
nodeMap=NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Array of name for the material
|
|
|
|
// No skeleton shape
|
|
|
|
CMaxMeshBaseBuild maxBaseBuild;
|
|
|
|
if (coarseMesh)
|
|
|
|
|
|
|
|
nodeMap=NULL;
|
|
|
|
|
|
|
|
|
|
|
|
// Append material to the base
|
|
|
|
// Array of name for the material
|
|
|
|
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, parentMatrix);
|
|
|
|
CMaxMeshBaseBuild maxBaseBuild;
|
|
|
|
|
|
|
|
|
|
|
|
// Get the node matrix
|
|
|
|
// Append material to the base
|
|
|
|
Matrix3 nodeMatrixMax;
|
|
|
|
buildBaseMeshInterface (buildBaseMesh, maxBaseBuild, node, time, parentMatrix);
|
|
|
|
CMatrix nodeMatrix;
|
|
|
|
|
|
|
|
getLocalMatrix (nodeMatrixMax, node, time);
|
|
|
|
|
|
|
|
convertMatrix (nodeMatrix, nodeMatrixMax);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get the node to parent matrix
|
|
|
|
// Get the node matrix
|
|
|
|
CMatrix nodeToParentMatrix;
|
|
|
|
Matrix3 nodeMatrixMax;
|
|
|
|
nodeToParentMatrix = parentMatrix.inverted () * nodeMatrix;
|
|
|
|
CMatrix nodeMatrix;
|
|
|
|
|
|
|
|
getLocalMatrix (nodeMatrixMax, node, time);
|
|
|
|
|
|
|
|
convertMatrix (nodeMatrix, nodeMatrixMax);
|
|
|
|
|
|
|
|
|
|
|
|
// Fill the build interface of CMesh
|
|
|
|
// Get the node to parent matrix
|
|
|
|
CMesh::CMeshBuild buildMesh;
|
|
|
|
CMatrix nodeToParentMatrix;
|
|
|
|
buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, nodeMap, nodeToParentMatrix);
|
|
|
|
nodeToParentMatrix = parentMatrix.inverted () * nodeMatrix;
|
|
|
|
|
|
|
|
|
|
|
|
// Append material names
|
|
|
|
// Fill the build interface of CMesh
|
|
|
|
isTransparent=false;
|
|
|
|
CMesh::CMeshBuild buildMesh;
|
|
|
|
isOpaque=false;
|
|
|
|
buildMeshInterface (*tri, buildMesh, buildBaseMesh, maxBaseBuild, node, time, nodeMap, nodeToParentMatrix);
|
|
|
|
for (uint i=0; i<maxBaseBuild.MaterialInfo.size(); i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Is opaque, transparent ?
|
|
|
|
|
|
|
|
if( buildBaseMesh.Materials[i+maxBaseBuild.FirstMaterial].getBlend() )
|
|
|
|
|
|
|
|
isTransparent=true;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
isOpaque=true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Push the name
|
|
|
|
// Append material names
|
|
|
|
listMaterialName.push_back (maxBaseBuild.MaterialInfo[i].MaterialName);
|
|
|
|
isTransparent=false;
|
|
|
|
}
|
|
|
|
isOpaque=false;
|
|
|
|
|
|
|
|
for (uint i=0; i<maxBaseBuild.MaterialInfo.size(); i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Is opaque, transparent ?
|
|
|
|
|
|
|
|
if( buildBaseMesh.Materials[i+maxBaseBuild.FirstMaterial].getBlend() )
|
|
|
|
|
|
|
|
isTransparent=true;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
isOpaque=true;
|
|
|
|
|
|
|
|
|
|
|
|
if( hasLightMap( node, time ) && _Options.bExportLighting )
|
|
|
|
// Push the name
|
|
|
|
calculateLM(&buildMesh, &buildBaseMesh, node, time, maxBaseBuild.FirstMaterial, _Options.OutputLightmapLog);
|
|
|
|
listMaterialName.push_back (maxBaseBuild.MaterialInfo[i].MaterialName);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MRM mesh ?
|
|
|
|
if( hasLightMap( node, time ) && _Options.bExportLighting )
|
|
|
|
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_MRM, 0) && (!coarseMesh) )
|
|
|
|
calculateLM(&buildMesh, &buildBaseMesh, node, time, maxBaseBuild.FirstMaterial, _Options.OutputLightmapLog);
|
|
|
|
{
|
|
|
|
|
|
|
|
// Build a MRM parameters block
|
|
|
|
|
|
|
|
CMRMParameters parameters;
|
|
|
|
|
|
|
|
buildMRMParameters (node, parameters);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Make a CMesh object
|
|
|
|
// MRM mesh ?
|
|
|
|
CMeshMRMGeom* meshMRMGeom=new CMeshMRMGeom;
|
|
|
|
if (getScriptAppData (&node, NEL3D_APPDATA_LOD_MRM, 0) && (!coarseMesh) )
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Build a MRM parameters block
|
|
|
|
|
|
|
|
CMRMParameters parameters;
|
|
|
|
|
|
|
|
buildMRMParameters (node, parameters);
|
|
|
|
|
|
|
|
|
|
|
|
// Get the blend shapes but in mesh build form
|
|
|
|
// Make a CMesh object
|
|
|
|
std::vector<CMesh::CMeshBuild*> bsList;
|
|
|
|
CMeshMRMGeom* meshMRMGeom=new CMeshMRMGeom;
|
|
|
|
getBSMeshBuild (bsList, node, time, nodeMap!=NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Build the mesh with the build interface
|
|
|
|
// Get the blend shapes but in mesh build form
|
|
|
|
meshMRMGeom->build (buildMesh, bsList, buildBaseMesh.Materials.size(), parameters);
|
|
|
|
std::vector<CMesh::CMeshBuild*> bsList;
|
|
|
|
|
|
|
|
getBSMeshBuild (bsList, node, time, nodeMap!=NULL);
|
|
|
|
|
|
|
|
|
|
|
|
// Return this pointer
|
|
|
|
// Build the mesh with the build interface
|
|
|
|
meshGeom=meshMRMGeom;
|
|
|
|
meshMRMGeom->build (buildMesh, bsList, buildBaseMesh.Materials.size(), parameters);
|
|
|
|
|
|
|
|
|
|
|
|
for (uint32 bsListIt = 0; bsListIt < bsList.size(); ++bsListIt)
|
|
|
|
// Return this pointer
|
|
|
|
delete bsList[bsListIt];
|
|
|
|
meshGeom=meshMRMGeom;
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Make a CMesh object
|
|
|
|
|
|
|
|
CMeshGeom* mGeom=new CMeshGeom;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Coarse mesh ?
|
|
|
|
#ifdef NL_DONT_FIND_MAX_CRASH
|
|
|
|
if (coarseMesh)
|
|
|
|
for (uint32 bsListIt = 0; bsListIt < bsList.size(); ++bsListIt)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Force vertex format
|
|
|
|
delete bsList[bsListIt];
|
|
|
|
buildMesh.VertexFlags=NL3D_COARSEMESH_VERTEX_FORMAT_EXPORT;
|
|
|
|
bsList[bsListIt] = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Make a CMesh object
|
|
|
|
|
|
|
|
CMeshGeom* mGeom=new CMeshGeom;
|
|
|
|
|
|
|
|
|
|
|
|
// Build the mesh with the build interface
|
|
|
|
// Coarse mesh ?
|
|
|
|
mGeom->build (buildMesh, buildBaseMesh.Materials.size());
|
|
|
|
if (coarseMesh)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Force vertex format
|
|
|
|
|
|
|
|
buildMesh.VertexFlags=NL3D_COARSEMESH_VERTEX_FORMAT_EXPORT;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return this pointer
|
|
|
|
// Build the mesh with the build interface
|
|
|
|
meshGeom=mGeom;
|
|
|
|
mGeom->build(buildMesh, buildBaseMesh.Materials.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Delete the triObject if we should...
|
|
|
|
// Return this pointer
|
|
|
|
if (deleteIt)
|
|
|
|
meshGeom=mGeom;
|
|
|
|
tri->DeleteMe();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Delete the triObject if we should...
|
|
|
|
|
|
|
|
if (deleteIt)
|
|
|
|
|
|
|
|
tri->MaybeAutoDelete();
|
|
|
|
|
|
|
|
tri = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|