コード例 #1
0
void Unreal3DExport::ShowSummary()
{
    
    // Progress
    pInt->ProgressUpdate(Progress);

    // Display Summary
    if( bShowPrompts )
    {
        ProgressMsg.printf(GetString(IDS_INFO_SUMMARY)
            , hAnim.NumFrames
            , hData.NumPolys
            , hData.NumVertices);

        if( bMaxResolution )
        {
            TSTR buf;
            buf.printf(GetString(IDS_INFO_DIDPRECISION)
                , FileName);
            ProgressMsg += buf;
        }

        MaxMsgBox(pInt->GetMAXHWnd(),ProgressMsg.data(),ShortDesc(),MB_OK|MB_ICONINFORMATION);
    }
}
コード例 #2
0
/////////////////////////////////////////////////////////////////////////////
// CMaxMaterialCollection
STDMETHODIMP CMaxMaterialCollection::FinalConstruct()
{
	HRESULT hr = E_FAIL, hr2 = E_FAIL;
	//simply make a reference to the scene material collection
	MtlBaseLib* pMtlLib = GetCOREInterface()->GetSceneMtls();
	mLastSceneMtlLibSize = 0;

#ifdef PERSIST_SCRATCH
	mpScratchMtlLib = NULL;
#endif

	assert(pMtlLib);

	//RK: 10/21/04 -- this forces ACT toolkit to initialize at startup and avoids delays during material assignment.
	CComDispatchDriver act;
	/*
		FIXME: Use the .NET wrappers directly instead of this;
		act.CoCreateInstance( L"Autodesk.Act.Core.ContentSerializer" );

		For some reason, the prog ID above is not being registered with the version
		we now install with Max 9, and I've had to resort to using the CLSID directly.

		Either we have the wrong version, or the new DLL just doesn't register its
		prog ID.  (more likely it's the former)
	*/
	CLSID clsidCore;
	hr = CLSIDFromString(L"{978C551B-5919-42F7-81AB-690D66AB7B78}", &clsidCore);

	if( SUCCEEDED(hr) )
		hr = act.CoCreateInstance( clsidCore );

	if (SUCCEEDED(hr))
	{
		CComVariant xml(L"<Material><StandardMtl name=\"Test\" /></Material>");
		CComPtr<IUnknown> mtl;
		hr2 = mtl.CoCreateInstance( L"Autodesk.Act.Content.Material");
		hr2 = act.Invoke1( L"DeserializeString", &xml );
	}
	if ( FAILED(hr) || FAILED(hr2) )
	{
		if (GetCOREInterface()->GetQuietMode())
			GetCOREInterface()->Log()->LogEntry(SYSLOG_ERROR,NO_DIALOG, TSTR(GetString(IDS_PROJNAME)), TSTR(GetString(IDS_ACT_REGISTRATION_FAILED)));
		else
			MaxMsgBox( GetCOREInterface()->GetMAXHWnd(), TSTR(GetString(IDS_ACT_REGISTRATION_FAILED)), TSTR(GetString(IDS_PROJNAME)), MB_OK );
	}
	assert(SUCCEEDED(hr) && SUCCEEDED(hr2));

	//RK: This forces XMlmtl to initialize at startup.
	CComPtr<IVIZPointerClient> pPointerClient;
	hr = GetXMLImpExp(&pPointerClient);
	assert(SUCCEEDED(hr));

#ifdef RECYCLE_MATS
#endif

	RegisterNotification(NotifyProc, this, NOTIFY_FILE_PRE_OPEN);
	RegisterNotification(NotifyProc, this, NOTIFY_FILE_POST_OPEN);
    RegisterNotification(NotifyProc, this, NOTIFY_FILE_OPEN_FAILED);
	RegisterNotification(NotifyProc, this, NOTIFY_FILE_PRE_MERGE);
	RegisterNotification(NotifyProc, this, NOTIFY_FILE_POST_MERGE);
	RegisterNotification(NotifyProc, this, NOTIFY_FILE_PRE_SAVE);
	RegisterNotification(NotifyProc, this, NOTIFY_FILE_POST_SAVE);
	RegisterNotification(NotifyProc, this, NOTIFY_PRE_IMPORT);
	RegisterNotification(NotifyProc, this, NOTIFY_POST_IMPORT);
	RegisterNotification(NotifyProc, this, NOTIFY_SYSTEM_PRE_NEW);
	RegisterNotification(NotifyProc, this, NOTIFY_SYSTEM_POST_NEW);
	RegisterNotification(NotifyProc, this, NOTIFY_SYSTEM_PRE_RESET);
	RegisterNotification(NotifyProc, this, NOTIFY_SYSTEM_POST_RESET);
	RegisterNotification(NotifyProc, this, NOTIFY_SCENE_UNDO);
	RegisterNotification(NotifyProc, this, NOTIFY_SCENE_REDO);
#ifdef SUSPEND_UNDO
	RegisterNotification(NotifyProc, this, NOTIFY_SCENE_PRE_UNDO);
	RegisterNotification(NotifyProc, this, NOTIFY_SCENE_PRE_REDO);
#endif

	RegisterNotification(NotifyProc, (void *)this, NOTIFY_MEDIT_SHOW);

#ifdef TP_SUSPEND_FOR_FILELINK
	RegisterNotification(NotifyProc, this, NOTIFY_FILELINK_PRE_BIND		);
	RegisterNotification(NotifyProc, this, NOTIFY_FILELINK_POST_BIND	);
	RegisterNotification(NotifyProc, this, NOTIFY_FILELINK_PRE_DETACH	);
	RegisterNotification(NotifyProc, this, NOTIFY_FILELINK_POST_DETACH	);
	RegisterNotification(NotifyProc, this, NOTIFY_FILELINK_PRE_RELOAD	);
	RegisterNotification(NotifyProc, this, NOTIFY_FILELINK_POST_RELOAD	);
	RegisterNotification(NotifyProc, this, NOTIFY_FILELINK_PRE_ATTACH	);
	RegisterNotification(NotifyProc, this, NOTIFY_FILELINK_POST_ATTACH	);
#endif

	//and finally a mechanism for other parts of the system to actively suspend TP
	RegisterNotification(NotifyProc, this, NOTIFY_TOOLPALETTE_MTL_SUSPEND	);
	RegisterNotification(NotifyProc, this, NOTIFY_TOOLPALETTE_MTL_RESUME	);

	//for DID 642266, pre and post cloning 
	RegisterNotification(NotifyProc, this, NOTIFY_PRE_NODES_CLONED	);
	RegisterNotification(NotifyProc, this, NOTIFY_POST_NODES_CLONED	);
	


	RefResult res = ReplaceReference(SCENE_MTLLIB_REFNUM, (RefTargetHandle) pMtlLib);
#ifdef PERSIST_SCRATCH
	res = ReplaceReference(SCRATCH_MTLLIB_REFNUM, (RefTargetHandle) &theScratchMtlLib);
#endif

	Resume();
	if(res == REF_SUCCEED)
		hr = S_OK;
	return hr;
}
コード例 #3
0
ファイル: MxActor.cpp プロジェクト: ani19tha/dynamica
NxActor* MxActor::createNxActor()
{
	if (m_bulletBody)
	{
		MaxMsgBox(NULL, _T("Error: body was already added to the dynamics world"), _T("Error"), MB_OK);
		return 0;
	}

	// find proxy node
	m_proxyNode = NULL;
	TSTR str = MxUserPropUtils::GetUserPropStr(m_node, "Proxy_Geometry");
	char* proxyName = str.data();
	if(proxyName && strlen(proxyName) > 0 && (stricmp(proxyName, "<None>") != 0))
	{
		m_proxyNode = GetCOREInterface()->GetINodeByName(proxyName);
	}

	//
	
	ccMaxNode* pActorNode = ccMaxWorld::FindNode(m_node);
	assert(pActorNode);
	maxNodeActor = pActorNode;

	maxNodeProxy = NULL;
	if(m_proxyNode)
	{
		maxNodeProxy       = ccMaxWorld::FindNode(m_proxyNode);
		assert(maxNodeProxy);
		//Point3 p1 = maxNodeActor->PhysicsNodePoseTM.GetRow(3), p2 = maxNodeProxy->PhysicsNodePoseTM.GetRow(3);
		Point3 p1 = maxNodeActor->NodePosInPhysics, p2 = maxNodeProxy->NodePosInPhysics;
		ProxyDistance = p1 - p2;
	}

	NxActorDesc&  actorDesc  = m_desc;
	NxBodyDesc&   bodyDesc   = m_bodyDesc;
	//LoadParameters(actorDesc, bodyDesc);
	actorDesc.globalPose = pActorNode->PhysicsNodePoseTM;//MxMathUtils::MaxMatrixToNx(pActorNode->PhysicsNodePoseTM);
	SaveLastPose(pActorNode->PhysicsNodePoseTM);

	//m_bodydesc.solverIterationCount = (NxU32)mSetting_solveriterationcount;   // support it in future?

	std::vector<INode*> stack;
	std::vector<INode*> shapes;

	//Check if the object is using a proxy, in that case only those shapes should be added
	INode* current = m_node;
	if(m_proxyNode)
		current = m_proxyNode;
	stack.push_back(current);
	//DEBUG_S("List collision shapes");
	while (stack.size() > 0)
	{
		current = stack[0];
		if(stack.size() > 1)
		{
			stack[0] = stack.back();
		}
		stack.pop_back();

		if(current->EvalWorldState(0).obj->SuperClassID()==GEOMOBJECT_CLASS_ID)
		{
			shapes.push_back(current);
		}

		//go through grouped objects
		for(int i = 0; i < current->NumberOfChildren(); i++)
		{
			INode *c = current->GetChildNode(i);
			if (c->IsGroupMember()) 
			{
				stack.push_back(c);
			}
		}
	}

	if (shapes.size() == 0)
	{
		if (gCurrentstream) gCurrentstream->printf("Unable to add %s as an actor, it has no shapes.\n", m_node->GetName());
		return 0;
	}

	ccMaxNode* baseNode = pActorNode;
	if(maxNodeProxy)
	{
		baseNode = maxNodeProxy;
	}

	btAlignedObjectArray<btCollisionShape*> collisionShapes;
	btAlignedObjectArray<btTransform> localTransforms;



	for (int i = 0; i < shapes.size(); i++) 
	{
		INode* current = shapes[i];
		//DEBUG_F(" Debug adding shape node: %s\n", current->GetName());
		ccMaxNode* pn = ccMaxWorld::FindNode(current);
		assert(pn);
		btCollisionShape* collisionShape = createShape(actorDesc, pn, pActorNode);
		collisionShapes.push_back(collisionShape);

		btTransform localTrans;
		max2Bullet(actorDesc.localPose,localTrans);
		localTransforms.push_back(localTrans);
	}

	//create a rigid body and add it to the world
	if (collisionShapes.size())
	{
		btCollisionShape* collisionShape = 0;
		if (collisionShapes.size()==1)
		{
			collisionShape = collisionShapes[0];

		} else
		{
			btCompoundShape* compound = new btCompoundShape();
			for (int i=0;i<collisionShapes.size();i++)
			{
				compound->addChildShape(localTransforms[i],collisionShapes[i]);
			}
			//clear local pose
			actorDesc.localPose.IdentityMatrix();
			collisionShape = compound;
		}

		if (collisionShape)
		{
			btVector3 localInertia(0,0,0);
			if (actorDesc.mass)
			{
				collisionShape->calculateLocalInertia(actorDesc.mass,localInertia);
			}

			m_bulletBody = new btRigidBody(actorDesc.mass,0,collisionShape,localInertia);
			m_bulletBody->setUserPointer(this);

			btScalar restitution;
			if (MxUserPropUtils::GetUserPropFloat(m_node, "Restitution", restitution))
			{
				m_bulletBody->setRestitution(restitution);
			}
			btScalar staticFriction = 0.f;

			//take the maximum for now
			MxUserPropUtils::GetUserPropFloat(m_node, "StaticFriction", staticFriction);
			
			btScalar friction = 0.f;
			if (MxUserPropUtils::GetUserPropFloat(m_node, "Friction", friction))
			{
				if (staticFriction>friction)
					friction = staticFriction;

				m_bulletBody->setFriction(friction);
			}


//			char bla[1024];
//			sprintf(bla,"restitution=%f",restitution);
//			MaxMsgBox(NULL, _T(bla), _T("Error"), MB_OK);

			syncGlobalPose();
			

			gDynamicsWorld->addRigidBody(m_bulletBody);
//			MaxMsgBox(NULL, _T("adding rigid body"), _T("Error"), MB_OK);

		}
	}
	
	
	bool isvalid = actorDesc.isValid();
	actorDesc.name = m_node->GetName();
	//NxMat34 pose0 = actorDesc.globalPose;
	
	//m_actor = gPluginData->getScene()->createActor(actorDesc);
	//if(! m_actor) return 0;

	//NxMat34 pose1 = m_actor->getGlobalPose();
	// sometimes pose1 != pose0; it is strange
	//m_actor->userData = this;

	if(MxUserPropUtils::GetUserPropBool(m_node, "PutToSleep", false))
	{
		//m_actor->putToSleep();
	}
	// for collision force when contact happens
	/*
	NxU32 num = m_actor->getNbShapes();
	NxShape*const* ps = m_actor->getShapes();
	for(NxU32 i = 0; i < num; ++i)
	{
		NxShape* nxShape = ps[i];
		nxShape->setFlag(NX_SF_POINT_CONTACT_FORCE, true);
	}
	*/


	//save last pose
	Matrix3 poseTM = maxNodeActor->GetCurrentTM();
	SaveLastPose(poseTM);


	//return m_actor;
	return 0;
}
コード例 #4
0
ファイル: MxActor.cpp プロジェクト: ani19tha/dynamica
/*
  Use the shape of node to create Bullet shape for the actor. ActorNode is the main Max node.
*/
btCollisionShape* MxActor::createShape(NxActorDesc& actorDesc, ccMaxNode* node, ccMaxNode* actorNode)
{
	actorDesc.localPose.IdentityMatrix();

	btCollisionShape* shape = NULL;

	const TimeValue t = ccMaxWorld::MaxTime();
	Matrix3 nodePose = node->PhysicsNodePoseTM;

//	MaxMsgBox(NULL, _T("createShape"), _T("Error"), MB_OK);

	int geomType = MxUserPropUtils::GetUserPropInt(m_node, "GeometryType",1);
	NxShapeType type = node->ShapeType;

	//first apply manual overrides
	switch (geomType)
	{
	case 2:
		{
			type = NX_SHAPE_SPHERE;
			break;
		}
	case 3:
		{
			type = NX_SHAPE_BOX;
			break;
		}
	case 4:
		{
			type = NX_SHAPE_CAPSULE;
			break;
		}
	case 5:
		{
			type = NX_SHAPE_CONVEX;
			break;
		}
	case 6:
		{
			type = NX_SHAPE_MESH;
			break;
		}
	default:
		{
			
		}
	};

	actorDesc.localPose = node->PhysicsNodePoseTM * actorNode->PhysicsNodePoseTMInv;

	switch (type)
	{
	case NX_SHAPE_SPHERE:
		{
			btScalar radius = node->PrimaryShapePara.Radius;
			shape = new btSphereShape(radius);
			break;
		};
	case NX_SHAPE_BOX:
		{
			//adjust for difference in pivot points between 3ds max and Bullet (Bullet uses the box center)
			Matrix3 offset;
			offset.IdentityMatrix();
			offset.SetTrans(2,node->PrimaryShapePara.BoxDimension.z());

			actorDesc.localPose = actorDesc.localPose * offset;

			shape = new btBoxShape(node->PrimaryShapePara.BoxDimension.absolute());

			break;
		}
	case NX_SHAPE_CAPSULE:
		{

			char bla[1024];
			sprintf(bla,"capsule not properly supported yet, radius=%f,height=%f",node->PrimaryShapePara.Radius,node->PrimaryShapePara.Height);
			MaxMsgBox(NULL, _T(bla), _T("Error"), MB_OK);

			shape = new btCapsuleShape(node->PrimaryShapePara.Radius,node->PrimaryShapePara.Height);
			break;
		}

	case NX_SHAPE_CONVEX:
		{
			if(m_proxyNode)
			{
				MaxMsgBox(NULL, _T("Error: convex shape proxy not supported (yet)"), _T("Error"), MB_OK);
				//d->meshData = MxUtils::nodeToNxConvexMesh(proxyMesh);
				//Matrix3 pose = nodePose * actorNode->PhysicsNodePoseTMInv;
				//d->localPose = MxMathUtils::MaxMatrixToNx(pose);
			}
			else
			{
				if(node->SimpleMesh.numFaces > 255)
				{
					MaxMsgBox(NULL, _T("Error: number of vertices in a convex shape should be less than 256"), _T("Error"), MB_OK);
					//warning/Error
				} else
				{

					BOOL needDel = FALSE;
					TriObject* tri = MxUtils::GetTriObjectFromNode(node->GetMaxNode(),0.f,needDel);
					if (tri)
					{
						int numVerts = tri->NumPoints();
						btConvexHullShape* convexHull = new btConvexHullShape();
						
						//for center of mass computation, simplify and assume mass is at the vertices
						btCompoundShape* compound = new btCompoundShape();
						btSphereShape sphere(0.1);
						btTransform tr;
						tr.setIdentity();
						btAlignedObjectArray<btScalar> masses;
						btScalar childMass = actorDesc.mass/(btScalar)numVerts;


						for (int i=0;i<numVerts;i++)
						{
							btVector3 pt(tri->GetPoint(i).x,tri->GetPoint(i).y,tri->GetPoint(i).z);
							convexHull->addPoint(pt);
							tr.setOrigin(pt);
							compound->addChildShape(tr,&sphere);
							masses.push_back(childMass);
						}
						
						btTransform principal;
						btVector3 inertia;
						compound->calculatePrincipalAxisTransform(&masses[0],principal,inertia);

						
						delete compound;

						btTransform principalInv = principal.inverse();
						compound = new btCompoundShape();
						compound->addChildShape(principalInv,convexHull);
						shape = compound;

						Matrix3 offset;
						bullet2Max(principal,offset);
						actorDesc.localPose = actorDesc.localPose * offset;


						if (needDel)
							delete tri;
					}
					
					

				}
				//d->meshData = MxUtils::nodeToNxConvexMesh(node->SimpleMesh);
				//Matrix3 pose = nodePose * actorNode->PhysicsNodePoseTMInv;
				//d->localPose = MxMathUtils::MaxMatrixToNx(pose);
			}
			break;
		}
	case 	NX_SHAPE_MESH:
		{

			

			BOOL needDel = FALSE;
			TriObject* tri = MxUtils::GetTriObjectFromNode(node->GetMaxNode(),0.f,needDel);

			if (tri)
			{
				int numVerts = tri->NumPoints();
				btTriangleMesh* meshInterface = new btTriangleMesh();
				Mesh& mesh = tri->GetMesh();

				if (mesh.getNumFaces()>0)
				{
					for (int i=0;i<mesh.getNumFaces();i++)
					{
						Point3 p0=tri->GetPoint(mesh.faces[i].v[0]);
						Point3 p1=tri->GetPoint(mesh.faces[i].v[1]);
						Point3 p2=tri->GetPoint(mesh.faces[i].v[2]);

						meshInterface->addTriangle( btVector3(p0.x,p0.y,p0.z),btVector3(p1.x,p1.y,p1.z),btVector3(p2.x,p2.y,p2.z));
					}

					
					if (actorDesc.mass>0)
					{
//						MaxMsgBox(NULL, _T("btGImpactMeshShape"), _T("Error"), MB_OK);

						btGImpactMeshShape* trimesh = new btGImpactMeshShape(meshInterface);
						shape = trimesh;

					} else
					{

//						MaxMsgBox(NULL, _T("btBvhTriangleMeshShape"), _T("Error"), MB_OK);
						btBvhTriangleMeshShape* trimesh = new btBvhTriangleMeshShape(meshInterface,true);
						shape = trimesh;
					}
					
					
				} else
				{
					MaxMsgBox(NULL, _T("Error: no faces"), _T("Error"), MB_OK);
				}
				if (needDel)
					delete tri;
				
			} else
			{
				MaxMsgBox(NULL, _T("Error: couldn't GetTriObjectFromNode"), _T("Error"), MB_OK);
			}

			break;
		}

	default:
		{
			MaxMsgBox(NULL, _T("unknown shape type"), _T("Error"), MB_OK);
		}
	};


#if 0
	NxShapeDesc* pd = NULL;
	NxShapeType type = node->ShapeType;
	PxSimpleMesh proxyMesh;
	Matrix3 nodePose = node->PhysicsNodePoseTM;
	if(m_proxyNode)
	{
		// for proxy, using mesh
		//type = NX_SHAPE_MESH;
		proxyMesh.clone(node->SimpleMesh);
		Point3 pos = nodePose.GetRow(3);
		pos = pos + ProxyDistance;
		nodePose.SetRow(3, pos);
	}
	if((type == NX_SHAPE_MESH) && (Interactivity != RB_STATIC))
	{
		type = NX_SHAPE_CONVEX;
	}
	//
	/*
	bool NeedCCDSkeleton = (Interactivity != RB_STATIC) && (MxUserPropUtils::GetUserPropBool(node->GetMaxNode(), "EnableCCD", false));
	if(NeedCCDSkeleton) 
	{
		NxPhysicsSDK* psdk = gPluginData->getPhysicsSDK();
		psdk->setParameter(NX_CONTINUOUS_CD, 1);
		psdk->setParameter(NX_CCD_EPSILON, 0.01f);
	}
	*/


	// create CCD skeleton for the shape
	//TODO("implement CCD skeleton creation");
	PX_CCD_SKELETON ccdType = (PX_CCD_SKELETON) MxUserPropUtils::GetUserPropInt(node->GetMaxNode(), "px_shape_ccdtype", 1);
	switch(type)
	{
	
	default:
		if (gCurrentstream) gCurrentstream->printf("Unable to create a shape of node \"%s\", unknown shape type: %d.\n", node->GetMaxNode()->GetName(), type);
		return false;
	}
	// load property settings and material things.
	//LoadShapeProperties(*pd, node->GetMaxNode());
	//CCD flag

	pd->name = node->GetMaxNode()->GetName();
	pd->userData = node;
	//
	bool isvalid = pd->isValid();
	actorDesc.shapes.push_back(pd);
#endif

	return shape;
}
コード例 #5
0
int Unreal3DExport::DoExport( const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options )
{
    int Result = FALSE;

    // Set a global prompt display switch
    bShowPrompts = suppressPrompts ? false : true;
    bExportSelected = (options & SCENE_EXPORT_SELECTED) ? true : false;
    
    // Get file names
    SplitFilename(TSTR(name), &FilePath, &FileName, &FileExt);

    if( MatchPattern(FileName,TSTR(_T("*_d")),TRUE)
    ||  MatchPattern(FileName,TSTR(_T("*_a")),TRUE) )
    {
        FileName = FileName.Substr(0,FileName.length()-2);
    }

    ModelFileName = FilePath + _T("\\") + FileName + TSTR(_T("_d")) + FileExt;
    AnimFileName = FilePath + _T("\\") + FileName + TSTR(_T("_a")) + FileExt;
    ScriptFileName = FilePath + _T("\\") + FileName + TSTR(_T("_rc.uc"));


    // Open Log
    fLog = _tfopen(FilePath + _T("\\") + FileName + _T(".log") ,_T("wb"));

    // Init
    pInt = GetCOREInterface();
    pInt->ProgressStart( GetString(IDS_INFO_INIT), TRUE, fn, this);
    Progress += U3D_PROGRESS_INIT;

    try 
    {
        MyErrorProc pErrorProc;
        SetErrorCallBack(&pErrorProc);

        ReadConfig();


        //if(bShowPrompts)
        /*DialogBoxParam(hInstance, 
                MAKEINTRESOURCE(IDD_PANEL), 
                GetActiveWindow(), 
                Unreal3DExportOptionsDlgProc, (LPARAM)this);*/

	    //if(showPrompts) 
	    {
		    // Prompt the user with our dialogbox, and get all the options.
		    if(!DialogBoxParam(hInstance, 
				MAKEINTRESOURCE(IDD_PANEL), 
				GetActiveWindow(), 
				Unreal3DExportOptionsDlgProc, (LPARAM)this)) 
            {
			    throw CancelException();
		    }
	    }

        // Enumerate interesting nodes
        Init();

        // Fetch data from nodes
        GetTris();
        GetAnim();

        // Prepare data for writing
        Prepare();     

        // Write to files
        WriteScript();
        WriteModel();   
        WriteTracking();

        // Show optional summary
        ShowSummary();

        WriteConfig();

        Result = IMPEXP_SUCCESS;
    }
    catch( CancelException& )
    {
        Result = IMPEXP_CANCEL;
    }
    catch( MAXException& e )
    {
        if( bShowPrompts && !e.message.isNull() )
        {
            MaxMsgBox(pInt->GetMAXHWnd(),e.message,ShortDesc(),MB_OK|MB_ICONERROR);
        }

        Result = IMPEXP_FAIL;
    }

    // Release scene
    if( pScene != NULL )
    {
        pScene->ReleaseIGame();
        pScene = NULL;
    }

    // Close files
    fclosen(fMesh);
    fclosen(fAnim);
    fclosen(fLog);
    fclosen(fScript);
    
    // Return to MAX
    pInt->ProgressEnd();  
    return Result;
}