Beispiel #1
0
int MarketDefaultTest::Tester::verifyMtl(Mtl* m, Class_ID id, const TCHAR* name)
{
	int errors = 0;

	if (m == NULL) {
		mStatus.message(kErrorMessage, _T("Error reading %s\r\n"), name);
		mStatus.message(kErrorMessage, _T("Could not create material\r\n"));
		++errors;
	}
	else {
		if (m->SuperClassID() != MATERIAL_CLASS_ID) {
			mStatus.message(kErrorMessage, _T("Error reading %s\r\n"), name);
			mStatus.message(kErrorMessage, _T("Expected material, got super-class %x\r\n"),
				m->SuperClassID());
			++errors;
		}
		else if (m->ClassID() != id) {
			mStatus.message(kErrorMessage, _T("Error reading %s\r\n"), name);
			mStatus.message(kErrorMessage, _T("Expected class id %x %x, got class %x %x\r\n"),
				id.PartA(), id.PartB(),
				m->ClassID().PartA(), m->ClassID().PartB());
			++errors;
		}
		m->DeleteThis();
	}

	return errors;
}
Beispiel #2
0
Modifier *CMaxMesh::FindMorpherModifier(INode *pINode)
{
    // get the object reference of the node
    Object *pObject;
    pObject = pINode->GetObjectRef();
    if(pObject == 0) return 0;

    // loop through all derived objects
    while(pObject->SuperClassID() == GEN_DERIVOB_CLASS_ID)
    {
        IDerivedObject *pDerivedObject;
        pDerivedObject = static_cast<IDerivedObject *>(pObject);

        // loop through all modifiers
        int stackId;
        for(stackId = 0; stackId < pDerivedObject->NumModifiers(); stackId++)
        {
            // get the modifier
            Modifier *pModifier;
            pModifier = pDerivedObject->GetModifier(stackId);

      Class_ID id = pModifier->ClassID();
      char buf[512];
      sprintf(buf, "node %s modifier %d class %d:%d/0x%x:0x%x\n",
        pINode->GetName(), stackId, id.PartA(), id.PartB(), id.PartA(), id.PartB());
      ::OutputDebugStringA(buf);
            // check if we found the physique modifier
            if(pModifier->ClassID() == MR3_CLASS_ID)
      {
        ::OutputDebugStringA("that was it! the morpher I was looking for!\n");
        return pModifier;
      }
        }

        // continue with next derived object
        pObject = pDerivedObject->GetObjRef();
    }

    return 0;
}
Beispiel #3
0
inline void MarketDefaultTest::Tester::format(Class_ID val)
{
	mStatus.message(kErrorMessage, _T("(%x, %x)"), val.PartA(), val.PartB());
}	
Beispiel #4
0
CInstanceGroup*	CExportNel::buildInstanceGroup(const vector<INode*>& vectNode, vector<INode*>& resultInstanceNode, TimeValue tvTime)
{
	// Extract from the node the name, the transformations and the parent

	CInstanceGroup::TInstanceArray aIGArray;
	uint32 i, nNumIG;
	uint32 j,k,m;

	aIGArray.empty ();
	resultInstanceNode.empty ();
	aIGArray.resize (vectNode.size());
	resultInstanceNode.resize (vectNode.size());

	int nNbInstance = 0;
	for (i = 0; i < vectNode.size(); ++i)
	{
		INode *pNode = vectNode[i];

		int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32);

		if ((nAccelType&3) == 0) // If not an accelerator
		if (!RPO::isZone (*pNode, tvTime))
		if (CExportNel::isMesh (*pNode, tvTime) || CExportNel::isDummy(*pNode, tvTime))
		{
			++nNbInstance;
		}
	}

	// Check integrity of the hierarchy and set the parents
	std::vector<INode*>::const_iterator it = vectNode.begin();
	nNumIG = 0;
	for (i = 0; i < (sint)vectNode.size(); ++i, ++it)
	{
		INode *pNode = *it;

		int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32);

		if ((nAccelType&3) == 0) // If not an accelerator
		if (!RPO::isZone( *pNode, tvTime ))
		if (CExportNel::isMesh( *pNode, tvTime ) || CExportNel::isDummy(*pNode, tvTime))
		{
			aIGArray[nNumIG].DontAddToScene = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_DONT_ADD_TO_SCENE, 0)?true:false;
			aIGArray[nNumIG].InstanceName = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_INSTANCE_NAME, "");
			resultInstanceNode[nNumIG] = pNode;
			if (aIGArray[nNumIG].InstanceName == "") // no instance name was set, takes the node name instead
			{
				aIGArray[nNumIG].InstanceName = pNode->GetName();
			}

			// Visible? always true, but if special flag for camera collision
			sint	appDataCameraCol= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_CAMERA_COLLISION_MESH_GENERATION, 0);
			aIGArray[nNumIG].Visible= appDataCameraCol!=3;


			INode *pParent = pNode->GetParentNode();

			// Set the DontCastShadow flag.
			aIGArray[nNumIG].DontCastShadow= pNode->CastShadows()==0;

			// Set the Special DontCastShadow flag.
			aIGArray[nNumIG].DontCastShadowForInterior= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_LIGHT_DONT_CAST_SHADOW_INTERIOR, BST_UNCHECKED)?true:false;
			aIGArray[nNumIG].DontCastShadowForExterior= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_LIGHT_DONT_CAST_SHADOW_EXTERIOR, BST_UNCHECKED)?true:false;

			// Is the pNode has the root node for parent ?
			if( pParent->IsRootNode() == 0 )
			{
				// Look if the parent is in the selection
				int nNumIG2 = 0;
				for (j = 0; j < vectNode.size(); ++j)
				{
					INode *pNode2 = vectNode[j];

					int nAccelType2 = CExportNel::getScriptAppData (pNode2, NEL3D_APPDATA_ACCEL, 32);
					if ((nAccelType2&3) == 0) // If not an accelerator
					if (!RPO::isZone( *pNode2, tvTime ))
					if (CExportNel::isMesh( *pNode2, tvTime ))
					{
						if (pNode2 == pParent)
							break;
						++nNumIG2;
					}
				}
				if (nNumIG2 == nNbInstance)
				{
					// The parent is not selected ! link to root
					aIGArray[nNumIG].nParent = -1;
				}
				else
				{
					aIGArray[nNumIG].nParent = nNumIG2;
				}
			}
			else
			{
				aIGArray[nNumIG].nParent = -1;
			}
			++nNumIG;
		}
	}
	aIGArray.resize( nNumIG );
	resultInstanceNode.resize( nNumIG );

	// Build the array of node
	vGlobalPos = CVector(0,0,0);
	nNumIG = 0;
	it = vectNode.begin();
	for (i = 0; i < (sint)vectNode.size(); ++i, ++it)
	{
		INode *pNode = *it;

		int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32);

		if ((nAccelType&3) == 0) // If not an accelerator
		if (!RPO::isZone (*pNode, tvTime))
		if (CExportNel::isMesh (*pNode, tvTime) || CExportNel::isDummy(*pNode, tvTime))
		{
			CVector vScaleTemp;
			CQuat qRotTemp;
			CVector vPosTemp;

			// Get Nel Name for the object.
			aIGArray[nNumIG].Name= CExportNel::getNelObjectName(*pNode);

			//Get the local transformation matrix
			Matrix3 nodeTM = pNode->GetNodeTM(0);
			INode *pParent = pNode->GetParentNode();
			Matrix3 parentTM = pParent->GetNodeTM(0);
			Matrix3 localTM	= nodeTM*Inverse(parentTM);

			// Extract transformations
			CExportNel::decompMatrix (vScaleTemp, qRotTemp, vPosTemp, localTM);
			aIGArray[nNumIG].Rot   = qRotTemp;
			aIGArray[nNumIG].Pos   = vPosTemp;
			aIGArray[nNumIG].Scale = vScaleTemp;
			vGlobalPos += vPosTemp;
			++nNumIG;
		}
	}
	// todo Make this work (precision):
	/*
	vGlobalPos = vGlobalPos / nNumIG;
	for (i = 0; i < nNumIG; ++i)
		aIGArray[i].Pos -= vGlobalPos;
	*/

	vGlobalPos = CVector(0,0,0); // Temporary !!!

	// Accelerator Portal/Cluster part
	//=================

	// Creation of all the clusters
	vector<CCluster> vClusters;
	it = vectNode.begin();
	for (i = 0; i < (sint)vectNode.size(); ++i, ++it)
	{
		INode *pNode = *it;

		int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, NEL3D_APPDATA_ACCEL_DEFAULT);
		bool bFatherVisible = nAccelType&NEL3D_APPDATA_ACCEL_FATHER_VISIBLE?true:false;
		bool bVisibleFromFather = nAccelType&NEL3D_APPDATA_ACCEL_VISIBLE_FROM_FATHER?true:false;
		bool bAudibleLikeVisible = (nAccelType&NEL3D_APPDATA_ACCEL_AUDIBLE_NOT_LIKE_VISIBLE)?false:true;
		bool bFatherAudible = bAudibleLikeVisible ? bFatherVisible : nAccelType&NEL3D_APPDATA_ACCEL_FATHER_AUDIBLE?true:false;
		bool bAudibleFromFather = bAudibleLikeVisible ? bVisibleFromFather : nAccelType&NEL3D_APPDATA_ACCEL_AUDIBLE_FROM_FATHER?true:false;

		if ((nAccelType&NEL3D_APPDATA_ACCEL_TYPE) == NEL3D_APPDATA_ACCEL_CLUSTER) // If cluster
		if (!RPO::isZone (*pNode, tvTime))
		if (CExportNel::isMesh(*pNode, tvTime))
		{
			CCluster clusterTemp;
			std::string temp;

			temp = CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_SOUND_GROUP, "no sound");
			clusterTemp.setSoundGroup(temp != "no sound" ? temp : "");
			temp = CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_ENV_FX, "no fx");
			clusterTemp.setEnvironmentFx(temp != "no fx" ? temp : "");

			CMesh::CMeshBuild *pMB;
			CMeshBase::CMeshBaseBuild *pMBB;
			pMB = createMeshBuild (*pNode, tvTime, pMBB);

			convertToWorldCoordinate( pMB, pMBB );

			for (j = 0; j < pMB->Faces.size(); ++j)
			{
				if (!clusterTemp.makeVolume (pMB->Vertices[pMB->Faces[j].Corner[0].Vertex],
											 pMB->Vertices[pMB->Faces[j].Corner[1].Vertex],
											 pMB->Vertices[pMB->Faces[j].Corner[2].Vertex]) )
				{
					// ERROR : The volume is not convex !!!
					char tam[256];
					sprintf(tam,"ERROR: The cluster %s is not convex.",vectNode[i]->GetName());
					//MessageBox(NULL,tam,"Error",MB_OK|MB_ICONERROR);
					nlwarning(tam);
				}
			}

			clusterTemp.FatherVisible = bFatherVisible;
			clusterTemp.VisibleFromFather = bVisibleFromFather;
			clusterTemp.FatherAudible = bFatherAudible;
			clusterTemp.AudibleFromFather = bAudibleFromFather;
			clusterTemp.Name = pNode->GetName();

			vClusters.push_back (clusterTemp);
			delete pMB;
			delete pMBB;
		}
	}

	// Creation of all the portals
	vector<CPortal> vPortals;
	it = vectNode.begin();
	for (i = 0; i < (sint)vectNode.size(); ++i, ++it)
	{
		INode *pNode = *it;

		int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32);

		if ((nAccelType&3) == 1) // If Portal
		if (!RPO::isZone (*pNode, tvTime))
		if (CExportNel::isMesh(*pNode, tvTime))
		{
			CPortal portalTemp;
			std::string temp;

			temp = CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_OCC_MODEL, "no occlusion");
			portalTemp.setOcclusionModel(temp != "no occlusion" ? temp : "");
			temp = CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_OPEN_OCC_MODEL, "no occlusion");
			portalTemp.setOpenOcclusionModel(temp != "no occlusion" ? temp : "");

			CMesh::CMeshBuild *pMB;
			CMeshBase::CMeshBaseBuild *pMBB;
			pMB = createMeshBuild (*pNode, tvTime, pMBB);

			convertToWorldCoordinate( pMB, pMBB );

			vector<sint32> poly;
			vector<bool> facechecked;
			facechecked.resize (pMB->Faces.size());
			for (j = 0; j < pMB->Faces.size(); ++j)
				facechecked[j] = false;

			poly.push_back(pMB->Faces[0].Corner[0].Vertex);
			poly.push_back(pMB->Faces[0].Corner[1].Vertex);
			poly.push_back(pMB->Faces[0].Corner[2].Vertex);
			facechecked[0] = true;
			for (j = 0; j < pMB->Faces.size(); ++j)
			if (!facechecked[j])
			{
				bool found = false;

				for(k = 0; k < 3; ++k)
				{
					for(m = 0; m < poly.size(); ++m)
					{
						if ((pMB->Faces[j].Corner[k].Vertex == poly[m]) &&
							(pMB->Faces[j].Corner[(k+1)%3].Vertex == poly[(m+1)%poly.size()]))
						{
							found = true;
							break;
						}
						if ((pMB->Faces[j].Corner[(k+1)%3].Vertex == poly[m]) &&
							(pMB->Faces[j].Corner[k].Vertex == poly[(m+1)%poly.size()]))
						{
							found = true;
							break;
						}
					}
					if (found)
						break;
				}
				if (found)
				{
					// insert an empty space in poly between m and m+1
					poly.resize (poly.size()+1);
					for (uint32 a = poly.size()-2; a > m; --a)
						poly[a+1] = poly[a];
					poly[m+1] = pMB->Faces[j].Corner[(k+2)%3].Vertex;
					facechecked[j] = true;
					j = 0;
				}
			}
			vector<CVector> polyv;
			polyv.resize (poly.size());
			for (j = 0; j < poly.size(); ++j)
				polyv[j] = pMB->Vertices[poly[j]];
			
			if (!portalTemp.setPoly (polyv))
			{
				// ERROR : Poly not convex, or set of vertices not plane
				char tam[256];
				sprintf(tam,"ERROR: The portal %s is not convex.",vectNode[i]->GetName());
				//MessageBox(NULL,tam,"Error",MB_OK|MB_ICONERROR);
				nlwarning(tam);
			}

			if (nAccelType&16) // is dynamic portal ?
			{
				string InstanceName = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_INSTANCE_NAME, "");
				if (!InstanceName.empty())
					portalTemp.setName (InstanceName);
				else
					portalTemp.setName (string(pNode->GetName()));
			}

			// Check if portal has 2 cluster
			int nNbCluster = 0;
			for (j = 0; j < vClusters.size(); ++j)
			{
				bool bPortalInCluster = true;
				for (k = 0; k < polyv.size(); ++k)
					if (!vClusters[j].isIn (polyv[k]) )
					{
						bPortalInCluster = false;
						break;
					}
				if (bPortalInCluster)
					++nNbCluster;
			}
			if (nNbCluster != 2)
			{
				// ERROR
				char tam[256];
				sprintf(tam,"ERROR: The portal %s has not 2 clusters but %d",vectNode[i]->GetName(), nNbCluster);
				//MessageBox(NULL,tam,"Error",MB_OK|MB_ICONERROR);
				nlwarning(tam);
			}


			vPortals.push_back (portalTemp);
			delete pMB;
			delete pMBB;
		}
	}

	// Link instance to clusters (an instance has a list of clusters)
	nNumIG = 0;
	it = vectNode.begin();
	for (i = 0; i < (sint)vectNode.size(); ++i, ++it)
	{
		INode *pNode = *it;

		int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32);

		if ((nAccelType&3) == 0) // If not an accelerator
		if (!RPO::isZone (*pNode, tvTime))
		if (CExportNel::isMesh (*pNode, tvTime) || CExportNel::isDummy(*pNode, tvTime))
		{
			if (nAccelType&32) // Is the flag clusterize set ?
			{
				// Test against all clusters

				// The list of vertices used to test against cluster
				std::vector<NLMISC::CVector> *testVertices;
				std::vector<NLMISC::CVector>       FXVertices;  // Used only if the obj is a fx. It contains the corners of the bbox.
				bool  buildMeshBBox = true;

				/** If it is a mesh, we build its bbox and transform in world
				  * 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
				  */
				Object *obj = pNode->EvalWorldState(tvTime).obj;
				// Check if there is an object
				if (obj)
				{
					Class_ID  clid = obj->ClassID();
					// is the object a particle system ?					
					if (clid.PartA() == NEL_PARTICLE_SYSTEM_CLASS_ID)
					{
						// build the shape from the file name
						std::string objName = CExportNel::getNelObjectName(*pNode); 						
						if (!objName.empty())
						{											
							NL3D::CShapeStream ss;
							NLMISC::CIFile iF;
							if (iF.open(objName.c_str()))
							{
								try
								{								
									iF.serial(ss);
									NL3D::CParticleSystemShape *pss = dynamic_cast<NL3D::CParticleSystemShape *>(ss.getShapePointer());
									if (!pss)
									{
										nlwarning("ERROR: Node %s shape is not a FX", CExportNel::getName(*pNode).c_str());
									}
									else
									{									
										NLMISC::CAABBox bbox;
										pss->getAABBox(bbox);
										// transform in world
										Matrix3 xForm = pNode->GetNodeTM(tvTime);
										NLMISC::CMatrix nelXForm;
										CExportNel::convertMatrix(nelXForm, xForm);									
										bbox = NLMISC::CAABBox::transformAABBox(nelXForm, bbox);
										// store vertices of the bbox in the list
										FXVertices.reserve(8);
										for(uint k = 0; k < 8; ++k)
										{
											FXVertices.push_back(CVector(((k & 1) ? 1 : -1) * bbox.getHalfSize().x + bbox.getCenter().x,
																		 ((k & 2) ? 1 : -1) * bbox.getHalfSize().y + bbox.getCenter().y,
																		 ((k & 4) ? 1 : -1) * bbox.getHalfSize().z + bbox.getCenter().z));
										}
										//
										testVertices = &FXVertices;
										buildMeshBBox = false;
									}
									delete ss.getShapePointer();
								}
								catch (NLMISC::Exception &e)
								{
									nlwarning(e.what());									
								}
							}							
							if (buildMeshBBox)
							{
								nlwarning("ERROR: Can't get bbox of a particle system from its shape, using helper bbox instead");
							}
						}
					}
				}

				CMesh::CMeshBuild *pMB = NULL;
				CMeshBase::CMeshBaseBuild *pMBB = NULL;

				if (buildMeshBBox)
				{				
					pMB = createMeshBuild (*pNode, tvTime, pMBB);
					convertToWorldCoordinate( pMB, pMBB );
					testVertices = &pMB->Vertices;
				}

				for(k = 0; k < vClusters.size(); ++k)
				{
					bool bMeshInCluster = false;

					for(j = 0; j < testVertices->size(); ++j)
					{
						if (vClusters[k].isIn ((*testVertices)[j]))
						{
							bMeshInCluster = true;
							break;
						}
					}

					if (bMeshInCluster)
					{
						aIGArray[nNumIG].Clusters.push_back (k);
					}
				}
				
				// debug purpose : to remove
				if (vClusters.size() > 0)
				if (aIGArray[nNumIG].Clusters.size() == 0)
				{
					char tam[256];
					sprintf(tam,"ERROR: Object %s is not attached to any cluster\nbut his flag clusterize is set", pNode->GetName());
					//MessageBox(NULL, tam, "Warning", MB_OK);
					nlwarning(tam);
				}
				// debug purpose : to remove

				delete pMB;
				delete pMBB;
			}
			
			++nNumIG;
		}
		// debug purpose : to remove
		/*
		if ((nAccelType&3) == 0) // If not an accelerator
		if (!(nAccelType&32))
		{
			char tam[256];
			sprintf(tam,"Object %s is not clusterized", pNode->GetName());
			MessageBox(NULL, tam, "Info", MB_OK);
		}
		*/
		// debug purpose : to remove

	}


	// PointLight part
	//=================
	bool	sunLightEnabled= false;
	sint	nNumPointLight = 0;
	vector<CPointLightNamed>	pointLights;
	pointLights.resize(vectNode.size());
	// For all nodes
	for (i = 0; i < (sint)vectNode.size(); ++i)
	{
		INode *pNode = vectNode[i];

		SLightBuild		sLightBuild;

		// If it is a Max Light.
		if ( sLightBuild.canConvertFromMaxLight(pNode, tvTime) )
		{
			// And if this light is checked to realtime export
			int		nRTExport= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_EXPORT_REALTIME_LIGHT, BST_CHECKED);
			if(nRTExport == BST_CHECKED)
			{
				// get Max Light info.
				sLightBuild.convertFromMaxLight(pNode, tvTime);

				// Skip if LightDir
				if(sLightBuild.Type != SLightBuild::LightDir)
				{
					// Fill PointLight Info.
					NL3D::CPointLightNamed	&plNamed= pointLights[nNumPointLight];

					// Position
					plNamed.setPosition(sLightBuild.Position);
					// Attenuation
					plNamed.setupAttenuation(sLightBuild.rRadiusMin, sLightBuild.rRadiusMax);
					// Colors
					// Ensure A=255 for localAmbient to work.
					NLMISC::CRGBA	ambient= sLightBuild.Ambient;
					ambient.A= 255;
					plNamed.setDefaultAmbient(ambient);
					plNamed.setAmbient(ambient);
					plNamed.setDefaultDiffuse(sLightBuild.Diffuse);
					plNamed.setDiffuse(sLightBuild.Diffuse);
					plNamed.setDefaultSpecular(sLightBuild.Specular);
					plNamed.setSpecular(sLightBuild.Specular);

					// GroupName.
					plNamed.AnimatedLight = sLightBuild.AnimatedLight;
					plNamed.LightGroup = sLightBuild.LightGroup;

					// Which light type??
					if(sLightBuild.bAmbientOnly || sLightBuild.Type== SLightBuild::LightAmbient)
					{
						plNamed.setType(CPointLight::AmbientLight);
						// Special ambient info
						int		nRTAmbAdd= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_REALTIME_AMBIENT_ADD_SUN, BST_UNCHECKED);
						plNamed.setAddAmbientWithSun(nRTAmbAdd==BST_CHECKED);
					}
					else if(sLightBuild.Type== SLightBuild::LightPoint)
					{
						plNamed.setType(CPointLight::PointLight);
					}
					else if(sLightBuild.Type== SLightBuild::LightSpot)
					{
						plNamed.setType(CPointLight::SpotLight);
						// Export Spot infos.
						plNamed.setupSpotDirection(sLightBuild.Direction);
						plNamed.setupSpotAngle(sLightBuild.rHotspot, sLightBuild.rFallof);
					}
					else
					{
						// What???
						nlstop;
					}


					// inc Size
					++nNumPointLight;
				}
			}

			// if this light is a directionnal and checked to export as Sun Light
			int		nExportSun= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_EXPORT_AS_SUN_LIGHT, BST_UNCHECKED);
			if(nExportSun== BST_CHECKED)
			{
				// get Max Light info.
				sLightBuild.convertFromMaxLight(pNode, tvTime);

				// Skip if not dirLight.
				if(sLightBuild.Type == SLightBuild::LightDir)
					sunLightEnabled= true;
			}
		}
	}
	// Good size
	pointLights.resize(nNumPointLight);


	// Build the ig
	//=================

	CInstanceGroup* pIG = new CInstanceGroup;

	// Link portals and clusters and create meta cluster if one
	pIG->build (vGlobalPos,  aIGArray, vClusters, vPortals, pointLights);

	// IG touched by sun ??
	pIG->enableRealTimeSunContribution(sunLightEnabled);

	return pIG;
}
	//------------------------------
	bool MorphControllerCreator::initializeChannelGeometry( morphChannel* channel, Object* geometryObject )
	{
		if ( !channel || !geometryObject )
		{
			return false;
		}

		Class_ID geometryObjectClassId = geometryObject->ClassID();
	
		MNMesh* polyMesh = 0;
		Mesh* triangleMesh = 0;
	
		if ( (geometryObjectClassId == EPOLYOBJ_CLASS_ID)  || (geometryObjectClassId.PartA() == POLYOBJ_CLASS_ID) )
		{
			polyMesh = &((PolyObject*)geometryObject)->GetMesh();
		}
		else if ( (geometryObjectClassId.PartA() == TRIOBJ_CLASS_ID) || (geometryObjectClassId.PartA() == EDITTRIOBJ_CLASS_ID ) )
		{
			triangleMesh = &((TriObject*)geometryObject)->GetMesh();
		}

		if ( !polyMesh && !triangleMesh )
		{
			// unsupported object type
			return true;
		}

		// Verify that the COLLADA source size matches the original mesh's vertex count
		int vertexCount = polyMesh ? polyMesh->VNum() : triangleMesh->numVerts;
		if (vertexCount != channel->mp->cache.count) 
		{
			return false;
		}

		// Set the channel's name and the necessary flags
		channel->mName = getObjectNameByObject(geometryObject).c_str();
		channel->mInvalid = false;
		channel->mActive = true;
		channel->mModded = true;


		// Allocate the channel's buffers and fill them with the relative vertex positions
		channel->AllocBuffers(vertexCount, vertexCount);
		channel->mSel.SetSize(vertexCount);
		channel->mSel.ClearAll();
		channel->mNumPoints = vertexCount;

		if ( polyMesh )
		{
			for (int i = 0; i < vertexCount; ++i)
			{
				channel->mPoints[i] = polyMesh->V( i )->p;
				channel->mDeltas[i] = (channel->mPoints[i] - channel->mp->cache.points[i]) / 100.0f;
				channel->mSel.Set(i, false);
				channel->mWeights[i] = 1.0f; // Not too sure of what the value should be here.
			}
		}
		else 
		{
			for (int i = 0; i < vertexCount; ++i)
			{
				channel->mPoints[i] = triangleMesh->verts[ i ];
				channel->mDeltas[i] = (channel->mPoints[i] - channel->mp->cache.points[i]) / 100.0f;
				channel->mSel.Set(i, false);
				channel->mWeights[i] = 1.0f; // Not too sure of what the value should be here.
			}
		}

		// Update all the UI stuff. Important? Must it be done for every channel?
		channel->mp->NotifyDependents(FOREVER,(PartID) PART_ALL,REFMSG_CHANGE);
		channel->mp->NotifyDependents(FOREVER,(PartID) PART_ALL,REFMSG_SUBANIM_STRUCTURE_CHANGED);
		channel->mp->Update_channelFULL();
		channel->mp->Update_channelParams();

		return true;
	}
AWDPrimitive * MaxAWDExporter::ExportPrimitiveGeom(Object * obj, char * name){
    Class_ID classId = obj->ClassID();
    if (classId.PartA() == EDITTRIOBJ_CLASS_ID || classId.PartA() == TRIOBJ_CLASS_ID ){
        return NULL;
    }
    AWD_primitive_type isPrimitve=AWD_PRIMITIVE_UNDEFINED;
    if (classId == Class_ID( BOXOBJ_CLASS_ID, 0 ))
        isPrimitve=AWD_PRIMITIVE_CUBE;
    if (classId == Class_ID( SPHERE_CLASS_ID, 0 ))
        isPrimitve=AWD_PRIMITIVE_SPHERE;
    if (classId == Class_ID( CYLINDER_CLASS_ID, 0 ))
        isPrimitve=AWD_PRIMITIVE_CYLINDER;
    if (classId == PLANE_CLASS_ID)
        isPrimitve=AWD_PRIMITIVE_PLANE;
    if (classId == Class_ID( CONE_CLASS_ID, 0 ))
        isPrimitve=AWD_PRIMITIVE_CONE;
    if (classId == Class_ID( TORUS_CLASS_ID, 0 ))
        isPrimitve=AWD_PRIMITIVE_TORUS;
    if (classId ==PYRAMID_CLASS_ID){}
    if (classId == GSPHERE_CLASS_ID){}
    if (classId == Class_ID( TUBE_CLASS_ID, 0 )){}
    if (classId == Class_ID( HEDRA_CLASS_ID, 0 )){}
	// KBEN:
    //if (classId == Class_ID( BOOLOBJ_CLASS_ID, 0 )){}
    if (isPrimitve!=AWD_PRIMITIVE_UNDEFINED){
        AWDPrimitive *awdGeom = (AWDPrimitive *)primGeocache->Get(obj);
        if (awdGeom == NULL) {
            IParamBlock* pblk = GetParamBlockByIndex((ReferenceMaker* )obj, 0);
            if (pblk){
                if (isPrimitve==AWD_PRIMITIVE_CUBE){
                    awdGeom=new AWDPrimitive(name, strlen(name), AWD_PRIMITIVE_CUBE);
                    awdGeom->set_Yoffset(pblk->GetFloat(BOXOBJ_HEIGHT) /2);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER1, pblk->GetFloat(BOXOBJ_WIDTH) * opts->Scale(), 100);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER2, pblk->GetFloat(BOXOBJ_HEIGHT) * opts->Scale(), 100);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER3, pblk->GetFloat(BOXOBJ_LENGTH) * opts->Scale(), 100);
                    awdGeom->add_bool_property(PROP_PRIM_BOOL1, false, true);
                    int cubeSegX=pblk->GetInt(BOXOBJ_WSEGS);
                    if(cubeSegX>100) cubeSegX=100;
                    int cubeSegY=pblk->GetInt(BOXOBJ_HSEGS);
                    if(cubeSegY>100) cubeSegY=100;
                    int cubeSegZ=pblk->GetInt(BOXOBJ_LSEGS);
                    if(cubeSegZ>100) cubeSegZ=100;
                    awdGeom->add_int_property(PROP_PRIM_INT1, cubeSegX, 1);
                    awdGeom->add_int_property(PROP_PRIM_INT2, cubeSegY, 1);
                    awdGeom->add_int_property(PROP_PRIM_INT3, cubeSegZ, 1);
                }
                if (isPrimitve==AWD_PRIMITIVE_SPHERE){
                    awdGeom=new AWDPrimitive(name, strlen(name), AWD_PRIMITIVE_SPHERE);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER1, pblk->GetFloat(SPHERE_RADIUS) * opts->Scale(), 50);
                    awdGeom->add_int_property(PROP_PRIM_INT1, pblk->GetInt(SPHERE_SEGS), 24);
                    //bool sphere_smooth=pblk->GetInt(SPHERE_SMOOTH);
                    //float sphere_hemisphere=pblk->GetFloat(SPHERE_HEMI);
                    //int sphere_radius=pblk->GetInt(SPHERE_SQUASH);
                    //int sphere_radius=pblk->GetInt(SPHERE_RECENTER);
                }
                if (isPrimitve==AWD_PRIMITIVE_CYLINDER){
                    awdGeom=new AWDPrimitive(name, strlen(name), AWD_PRIMITIVE_CYLINDER);
                    awdGeom->set_Yoffset(pblk->GetFloat(CYLINDER_HEIGHT) /2);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER1, pblk->GetFloat(CYLINDER_RADIUS) * opts->Scale(), 50);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER2, pblk->GetFloat(CYLINDER_RADIUS) * opts->Scale(), 50);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER3, pblk->GetFloat(CYLINDER_HEIGHT) * opts->Scale(), 100);
                    awdGeom->add_int_property(PROP_PRIM_INT1, pblk->GetInt(CYLINDER_SIDES), 16);
                    awdGeom->add_int_property(PROP_PRIM_INT2, pblk->GetInt(CYLINDER_SEGMENTS), 1);
                    //int cylinder_capsegments=pblk->GetInt(CYLINDER_CAPSEGMENTS);
                    //bool cylinder_slice_on=pblk->GetInt(CYLINDER_SLICEON);
                    //int box_depth_segs=pblk->GetInt(CYLINDER_SMOOTH);
                }
                if (isPrimitve==AWD_PRIMITIVE_CONE){
                    float cone_radius2=pblk->GetFloat(CONE_RADIUS2);
                    if (cone_radius2==0.0){
                        awdGeom=new AWDPrimitive(name, strlen(name), AWD_PRIMITIVE_CONE);
                        awdGeom->set_Yoffset(pblk->GetFloat(CONE_HEIGHT) /2);
                        awdGeom->add_number_property(PROP_PRIM_NUMBER1, pblk->GetFloat(CONE_RADIUS1) * opts->Scale(), 50);
                        awdGeom->add_number_property(PROP_PRIM_NUMBER2, pblk->GetFloat(CONE_HEIGHT) * opts->Scale(), 100);
                        awdGeom->add_int_property(PROP_PRIM_INT1, pblk->GetInt(CONE_SIDES), 16);
                        awdGeom->add_int_property(PROP_PRIM_INT2, pblk->GetFloat(CONE_SEGMENTS), 1);
                    }
                    else{
                        awdGeom=new AWDPrimitive(name, strlen(name), AWD_PRIMITIVE_CYLINDER);
                        awdGeom->set_Yoffset(pblk->GetFloat(CONE_HEIGHT) /2);
                        awdGeom->add_number_property(PROP_PRIM_NUMBER1, pblk->GetFloat(CONE_RADIUS2) * opts->Scale(), 50);
                        awdGeom->add_number_property(PROP_PRIM_NUMBER2, pblk->GetFloat(CONE_RADIUS1) * opts->Scale(), 50);
                        awdGeom->add_number_property(PROP_PRIM_NUMBER3, pblk->GetFloat(CONE_HEIGHT) * opts->Scale(), 100);
                        awdGeom->add_int_property(PROP_PRIM_INT1, pblk->GetInt(CONE_SIDES), 16);
                        awdGeom->add_int_property(PROP_PRIM_INT2, pblk->GetInt(CONE_SEGMENTS), 1);
                    }
                    //int cone_capSegments=pblk->GetInt(CONE_CAPSEGMENTS);
                    //int cone_smooth=pblk->GetInt(CONE_SMOOTH);
                    //int cone_slice_on=pblk->GetInt(CONE_SLICEON);
                }
                if (isPrimitve==AWD_PRIMITIVE_CAPSULE){//not in 3dsmax supported...
                    awdGeom=new AWDPrimitive(name, strlen(name), AWD_PRIMITIVE_CAPSULE);
                }
                if (isPrimitve==AWD_PRIMITIVE_TORUS){
                    awdGeom=new AWDPrimitive(name, strlen(name), AWD_PRIMITIVE_TORUS);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER1, pblk->GetFloat(TORUS_RADIUS) * opts->Scale(), 10);
                    awdGeom->add_number_property(PROP_PRIM_NUMBER2, pblk->GetFloat(TORUS_RADIUS2) * opts->Scale(), 100);
                    awdGeom->add_int_property(PROP_PRIM_INT1, pblk->GetInt(TORUS_SEGMENTS), 16);
                    //float torus_rotation=pblk->GetFloat(TORUS_ROTATION);
                    //float torus_twist=pblk->GetFloat(TORUS_TWIST);
                    //int torus_sides=pblk->GetInt(TORUS_SIDES);
                    //int torus_smooth=pblk->GetInt(TORUS_SMOOTH);
                    //int torus_slice_on=pblk->GetInt(TORUS_SLICEON);
                }
                awd->add_prim_block(awdGeom);
                primGeocache->Set(obj, awdGeom);
                return awdGeom;
            }
            else {
                IParamBlock2* pblk2 = GetParamBlock2ByIndex((ReferenceMaker* )obj, 0);
                if (pblk2){
                    if (isPrimitve==AWD_PRIMITIVE_PLANE){
                        awdGeom=new AWDPrimitive(name, strlen(name), AWD_PRIMITIVE_PLANE);
                        int numBlockparams=pblk2->NumParams();
                        int p=0;
                        for (p=0; p<numBlockparams; p++) {
                            ParamID pid = pblk2->IndextoID(p);
                            ParamDef def = pblk2->GetParamDef(pid);
                            ParamType2 paramtype = pblk2->GetParameterType(pid);
                            char * paramName=W2A(def.int_name);
                            if (paramtype==TYPE_FLOAT){
                                if (ATTREQ(paramName, "length"))
                                    awdGeom->add_number_property(PROP_PRIM_NUMBER2, pblk2->GetFloat(pid) * opts->Scale(), 100);
                                if (ATTREQ(paramName, "width"))
                                    awdGeom->add_number_property(PROP_PRIM_NUMBER1, pblk2->GetFloat(pid) * opts->Scale(), 100);
                            }
                            if (paramtype==TYPE_INT){
                                if (ATTREQ(paramName, "lengthsegs"))
                                   awdGeom->add_int_property(PROP_PRIM_INT2, pblk2->GetInt(pid), 1);
                                if (ATTREQ(paramName, "widthsegs"))
                                   awdGeom->add_int_property(PROP_PRIM_INT1, pblk2->GetInt(pid), 1);
                            }
                            free(paramName);
                        }
                    }
                    awd->add_prim_block(awdGeom);
                    primGeocache->Set(obj, awdGeom);
                    return awdGeom;
                }
            }
        }
        return awdGeom;
    }
    return NULL;
}