Changed: #929 Some reliability fixes for the max export plugin.
This commit is contained in:
parent
46de2a84b1
commit
f97b47eef1
18 changed files with 914 additions and 765 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue