Example #1
0
//=================================================================
// Methods for DumpModelTEP
//
Modifier *FindPhysiqueModifier (INode *nodePtr)
{
	// Get object from node. Abort if no object.
	Object *ObjectPtr = nodePtr->GetObjectRef();
	if (!ObjectPtr) return NULL;

	// Is derived object ?
	if (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID)
	{
		// Yes -> Cast.
		IDerivedObject *DerivedObjectPtr = static_cast<IDerivedObject*>(ObjectPtr);

		// Iterate over all entries of the modifier stack.
		int ModStackIndex = 0;
		while (ModStackIndex < DerivedObjectPtr->NumModifiers())
		{
			// Get current modifier.
			Modifier *ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);

			// Is this Physique ?
			if (ModifierPtr->ClassID() == Class_ID(	PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B) )
			{
				// Yes -> Exit.
				return ModifierPtr;
			}
			// Next modifier stack entry.
			ModStackIndex++;
		}
	}
	// Not found.
	return NULL;
}
Example #2
0
Modifier *CMaxMesh::FindSkinModifier(INode *pINode)
{
#if MAX_RELEASE >= 4000
	// 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);

			// check if we found the skin modifier
			if(pModifier->ClassID() == SKIN_CLASSID) return pModifier;
		}

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

	return 0;
}
Example #3
0
Modifier *CMaxMesh::FindPhysiqueModifier(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);

			// check if we found the physique modifier
			if(pModifier->ClassID() == Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B)) return pModifier;
		}

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

	return 0;
}
Example #4
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;
}
PaintDefromModData *PaintDeformTest::GetPMD(INode *pNode)
{
	ModContext *mc = NULL;

	Object* pObj = pNode->GetObjectRef();

	if (!pObj) return NULL;

	
	while (pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID && mc == NULL)
	{
		IDerivedObject* pDerObj = (IDerivedObject *)(pObj);
			
		int Idx = 0;

		while (Idx < pDerObj->NumModifiers())
		{
			// Get the modifier. 
			Modifier* mod = pDerObj->GetModifier(Idx);

			
			if (mod->ClassID() == PAINTDEFORMTEST_CLASS_ID)
			{
				// is this the correct Physique Modifier based on index?
				PaintDeformTest *pmod = (PaintDeformTest*)mod;
				if (pmod == this)
					{
					mc = pDerObj->GetModContext(Idx);
					break;
					}
			}

			Idx++;
		}

		pObj = pDerObj->GetObjRef();
	}

	if(!mc) return NULL;

	if ( !mc->localData ) return NULL;

	PaintDefromModData *bmd = (PaintDefromModData *) mc->localData;

	return bmd;

}
ISkin* CExporter::getISkinPtr(Object* object)
{
	assert(object != NULL);
	while (GEN_DERIVOB_CLASS_ID == object->SuperClassID())
	{
		IDerivedObject* pDerObj = static_cast<IDerivedObject*>(object);

		for (int i = 0; i < pDerObj->NumModifiers(); ++i)
		{
			Modifier* mod = pDerObj->GetModifier(i);
			if (SKIN_CLASSID == mod->ClassID())
			{
				return (ISkin*)(mod->GetInterface(I_SKIN));
			}
		}
		object = pDerObj->GetObjRef();
	}
	return NULL;
}
void HavokImport::HandleRagdollOnNonAccum(INode* accumChild, INode* ragdollParent)
{
	const int MaxChar = 512;
	char buffer[MaxChar];

	//Fix for nonaccumNodes

	//TSTR name(A2THelper(buffer, parent->GetName().c_str(), _countof(buffer)));
	ragdollParent->SetName(FormatText(TEXT("Ragdoll_%s"), accumChild->GetName()));

	Object *Obj = ragdollParent->GetObjectRef();

	if (Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID)
	{
		while (Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID) {
		
			IDerivedObject *DerObj = static_cast<IDerivedObject *> (Obj);
			const int nMods = DerObj->NumModifiers();
			for (int i = 0; i < nMods; i++)
			{
				Modifier *Mod = DerObj->GetModifier(i);
				if (Mod->ClassID() == HK_RIGIDBODY_MODIFIER_CLASS_ID)
				{
					ICustAttribContainer* cc = Mod->GetCustAttribContainer();
					if (cc)
					{
					//reset
						Mod->DeleteCustAttribContainer();

					}
					Mod->AllocCustAttribContainer();
					cc = Mod->GetCustAttribContainer();
					CustAttrib* c = (CustAttrib*)CreateInstance(CUST_ATTRIB_CLASS_ID, Class_ID(0x6e663460, 0x32682c72));
					IParamBlock2* custModParameters = c->GetParamBlock(0);
					custModParameters->SetValue(0, 0, accumChild, 0);

					cc->InsertCustAttrib(0, c);
				}
			}
			Obj = DerObj->GetObjRef();
		}
	}
}
Example #8
0
Modifier *FindSkinModifier (INode *node)
{
    Object* ObjectPtr = node->GetObjectRef();
    if (!ObjectPtr) return NULL;

    while (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID && ObjectPtr)
    {
        IDerivedObject *DerivedObjectPtr = (IDerivedObject *)(ObjectPtr);
        int ModStackIndex = 0;
        while (ModStackIndex < DerivedObjectPtr->NumModifiers())
        {
            Modifier* ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);
            if (ModifierPtr->ClassID() == SKIN_CLASSID)
                return ModifierPtr;
            ModStackIndex++;
        }
        ObjectPtr = DerivedObjectPtr->GetObjRef();
    }
    return NULL;
}
//----------------------------------------------------------------------------
void SceneBuilder::ApplyModifiers()
{
	// 遍历节点使用收集的修改器,当前唯一支持的修改器是skin。

	std::vector<ModifierInfo*>::iterator itI = mModifierList.begin();
	for (; itI!=mModifierList.end(); itI++)
	{
		ModifierInfo *info = *itI;
		
		std::vector<Modifier*>::iterator itJ = info->Modifiers.begin();
		for (; itJ!=info->Modifiers.end(); itJ++)
		{
			Modifier *modifier = *itJ;
			Class_ID id = modifier->ClassID();
			if (id == SKIN_CLASSID)
			{
				ProcessSkin(info->Node, modifier);
			}
		}
	}
}
// --[  Method  ]---------------------------------------------------------------
//
//  - Class     : CStravaganzaMaxTools
//
//  - prototype : Modifier* GetPhysiqueModifier(INode* pMaxNode)
//
//  - Purpose   : Returns the Physique modifier of a given node if present.
//
// -----------------------------------------------------------------------------
Modifier* CStravaganzaMaxTools::GetPhysiqueModifier(INode* pMaxNode)
{
	Object* pMaxObject = pMaxNode->GetObjectRef();

	if(!pMaxObject)
	{
		return NULL;
	}

	while(pMaxObject->SuperClassID() == GEN_DERIVOB_CLASS_ID && pMaxObject)
	{
		// Yes -> Cast.
		IDerivedObject* pMaxDerivedObject = (IDerivedObject *)(pMaxObject);				

		// Iterate over all entries of the modifier stack.
		int nModStackIndex = 0;

		while(nModStackIndex < pMaxDerivedObject->NumModifiers())
		{
			// Get current modifier.
			Modifier* pMaxModifier = pMaxDerivedObject->GetModifier(nModStackIndex);

			// Is this Physique?
			if(pMaxModifier->ClassID() == Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B))
			{
				return pMaxModifier;
			}

			nModStackIndex++;
		}

		pMaxObject = pMaxDerivedObject->GetObjRef();
	}

	// Not found.
	return NULL;
}
//----------------------------------------------------------------------------
bool SceneBuilder::Traverse(INode *maxNode, PX2::Node *relatParent)
{
	// movbale对应maxNode的父节点

	bool isHasSkin = false;

	// Modifier
	if (mSettings->IncludeModifiers)
	{
		ModifierInfo *modInfo = new0 ModifierInfo;
		CollectModifiers(maxNode, modInfo->Modifiers);
		if (modInfo->Modifiers.empty())
		{
			delete0(modInfo);
		}
		else
		{
			modInfo->Node = maxNode;
			mModifierList.push_back(modInfo);

			for (int i=0; i<(int)modInfo->Modifiers.size(); i++)
			{
				Modifier *modifier = modInfo->Modifiers[i];
				Class_ID id = modifier->ClassID();
				if (id == SKIN_CLASSID ||
					id == Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B))
				{
					isHasSkin = true;
				}
			}
		}
	}

	// Node
	const char *nodeName = maxNode->GetName();

	if(stricmp(nodeName, "PHYSICSDATA") == 0)
	{
	}
	else if(stricmp(nodeName, "PORTALDATA") == 0)
	{
	}

	PX2::Movable *child = 0;

	ObjectState objectState = maxNode->EvalWorldState(mTimeStart);
	bool supported = true;

	// Object
	if (objectState.obj)
	{
		switch (objectState.obj->SuperClassID())
		{
		case GEOMOBJECT_CLASS_ID:
			if (IsNodeRenderable(maxNode, objectState.obj))
				child = BuildGeometry(maxNode, relatParent, isHasSkin);
			else
				child = BuildNode(maxNode, relatParent);
			break;
		case CAMERA_CLASS_ID:
			// ToDo
			break;
		case LIGHT_CLASS_ID:
			if (mSettings->IncludeLights && !maxNode->IsHidden())
			{
				BuildLight(maxNode, relatParent);
			}
			break;
		case HELPER_CLASS_ID:
			//supported = false;
			child = BuildNode(maxNode, relatParent);
			break;
		default:
			assertion(false, "Some object type not supportted.");
			supported = false;
			break;
		}
	}

	// Keyframe
	if (child)
	{
		if (mSettings->IncludeKeyFrames)
			BuildKeyFrameController(maxNode, child);
		else
			BuildFrameController(maxNode, child);
	}

	// Child
	int numChildren = maxNode->NumberOfChildren();
	if (numChildren == 0)
		return true;

	PX2::Node *childNode = 0;
	childNode = PX2::DynamicCast<PX2::Node>(child);
	if (childNode == 0)
		return true;

	for (int i=0; i<numChildren; i++)
	{
		if (!Traverse(maxNode->GetChildNode(i), childNode) || mMax->GetCancel())
			return false;
	}

	return true;
}
Example #12
0
static void extractTriangleGeometry( GmModel* gm, INode* node, Mesh* mesh, Mtl* material )
{
#ifdef SGEXPORT_PHYSIQUE
	Modifier*			phyMod		= 0;
	IPhysiqueExport*	phyExport	= 0;
	IPhyContextExport*	mcExport	= 0;
#endif
	Modifier*			skinMod		= 0;
	ISkin*				skin		= 0;
	String				nodeName	( node->GetName() );

	try
	{
		// vertex transform to left-handed system
		Matrix3 pivot = TmUtil::getPivotTransform( node );
		Matrix3 vertexTM = pivot * s_convtm;
		bool insideOut = TmUtil::hasNegativeParity( pivot );

		/*Matrix4x4 pm = TmUtil::toLH( vertexTM );
		Debug::println( "Object {0} vertex local TM is", nodeName );
		Debug::println( "  {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(0,0), pm(0,1), pm(0,2), pm(0,3) );
		Debug::println( "  {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(1,0), pm(1,1), pm(1,2), pm(1,3) );
		Debug::println( "  {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(2,0), pm(2,1), pm(2,2), pm(2,3) );
		Debug::println( "  {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(3,0), pm(3,1), pm(3,2), pm(3,3) );*/

		// add vertex positions
		int vertices = mesh->getNumVerts();
		for ( int vi = 0 ; vi < vertices ; ++vi )
		{
			Point3 v = vertexTM * mesh->verts[vi];
			mb::Vertex* vert = gm->addVertex();
			vert->setPosition( v.x, v.y, v.z );
		}

		// add vertex weights (from Physique modifier)
#ifdef SGEXPORT_PHYSIQUE
		phyMod = PhyExportUtil::findPhysiqueModifier( node );
		if ( phyMod )
		{
			Debug::println( "  Found Physique modifier: {0}", gm->name );

			// get (possibly shared) Physique export interface
			phyExport = (IPhysiqueExport*)phyMod->GetInterface( I_PHYINTERFACE );
			if( !phyExport )
				throw Exception( Format("No Physique modifier export interface") );

			// export from initial pose?
			phyExport->SetInitialPose( false );
			
			// get (unique) context dependent export inteface
			mcExport = (IPhyContextExport*)phyExport->GetContextInterface( node );
			if( !mcExport )
				throw Exception( Format("No Physique modifier context export interface") );

			// convert to rigid for time independent vertex assignment
			mcExport->ConvertToRigid( true );

			// allow blending to export multi-link assignments
			mcExport->AllowBlending( true );

			// list bones
			Vector<INode*> bones( Allocator<INode*>(__FILE__,__LINE__) );
			PhyExportUtil::listBones( mcExport, bones );

			// add vertex weight maps
			for ( int i = 0 ; i < bones.size() ; ++i )
			{
				INode* bone = bones[i];
				String name = bone->GetName();
				mb::VertexMap* vmap = gm->addVertexMap( 1, name, mb::VertexMapFormat::VERTEXMAP_WEIGHT );
				PhyExportUtil::addWeights( vmap, bone, mcExport );
			}
		}
#endif // SGEXPORT_PHYSIQUE

		// add vertex weights (from Skin modifier)
		skinMod = SkinExportUtil::findSkinModifier( node );
		if ( skinMod )
		{
			skin = (ISkin*)skinMod->GetInterface(I_SKIN);
			require( skin );
			ISkinContextData* skincx = skin->GetContextInterface( node );
			require( skincx );
			Debug::println( "  Found Skin modifier: {0} ({1} bones, {2} points)", gm->name, skin->GetNumBones(), skincx->GetNumPoints() );
			
			if ( skincx->GetNumPoints() != gm->vertices() )
				throw Exception( Format("Only some vertices ({0}/{1}) of {2} are skinned", skincx->GetNumPoints(), gm->vertices(), gm->name) );

			// list bones
			Vector<INode*> bones( Allocator<INode*>(__FILE__,__LINE__) );
			SkinExportUtil::listBones( skin, bones );

			// add vertex weight maps
			for ( int i = 0 ; i < bones.size() ; ++i )
			{
				INode* bone = bones[i];
				String name = bone->GetName();
				mb::VertexMap* vmap = gm->addVertexMap( 1, name, mb::VertexMapFormat::VERTEXMAP_WEIGHT );
				SkinExportUtil::addWeights( vmap, bone, skin, skincx );
				//Debug::println( "    Bone {0} is affecting {1} vertices", name, vmap->size() );
			}

			// DEBUG: print skin node tm and initial object tm
			/*Matrix3 tm;
			int ok = skin->GetSkinInitTM( node, tm );
			require( ok == SKIN_OK );
			Debug::println( "  NodeInitTM of {0}", nodeName );
			TmUtil::println( tm, 4 );
			ok = skin->GetSkinInitTM( node, tm, true );
			require( ok == SKIN_OK );
			Debug::println( "  NodeObjectTM of {0}", nodeName );
			TmUtil::println( tm, 4 );*/

			// DEBUG: print bones
			/*Debug::println( "  bones of {0}:", nodeName );
			for ( int i = 0 ; i < bones.size() ; ++i )
			{
				Debug::println( "    bone ({0}): {1}", i, String(bones[i]->GetName()) );
				skin->GetBoneInitTM( bones[i], tm );
				Debug::println( "      InitNodeTM:" );
				TmUtil::println( tm, 6 );
				skin->GetBoneInitTM( bones[i], tm, true );
				Debug::println( "      InitObjectTM:" );
				TmUtil::println( tm, 6 );
			}*/

			// DEBUG: print bones used by the points
			/*for ( int i = 0 ; i < skincx->GetNumPoints() ; ++i )
			{
				int bonec = skincx->GetNumAssignedBones(i);
				Debug::println( "    point {0} has {1} bones", i, bonec );
				for ( int k = 0 ; k < bonec ; ++k )
				{
					int boneidx = skincx->GetAssignedBone( i, k );
					float w = skincx->GetBoneWeight( i, k );
					Debug::println( "    point {0} boneidx ({1}): {2}, weight {3}", i, k, boneidx, w );
				}
			}*/
		}

		// ensure clockwise polygon vertex order
		int vx[3] = {2,1,0};
		if ( insideOut )
		{
			int tmp = vx[0];
			vx[0] = vx[2];
			vx[2] = tmp;
		}
	
		// list unique materials used by the triangles
		Vector<ShellMaterial> usedMaterials( Allocator<ShellMaterial>(__FILE__,__LINE__) );
		if ( material )
		{
			for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi )
			{
				Face& face = mesh->faces[fi];
				
				int mergesubmaterial = -1;
				int originalsubmaterial = -1;

				for ( int j = 0; j < material->NumSubMtls(); ++j)
				{
					// Get Sub Material Slot name 
					TSTR name = material->GetSubMtlSlotName(j);

					// Light maps are stored in sub material slot named "Baked Material"
					if ( strcmp( name, "Baked Material" ) == 0 ) 
						mergesubmaterial = j;
					else 
						originalsubmaterial = j;				
				}

				if ( mergesubmaterial != -1 ) // A baked material was found, shell materials will be created
				{
					Mtl* mat = material->GetSubMtl( originalsubmaterial );
					Mtl* bakedmtl = material->GetSubMtl( mergesubmaterial );
				
					if ( mat->NumSubMtls() > 0 ) // Check for nested multi-material
					{
						for ( int j = 0; j < mat->NumSubMtls(); ++j)
							usedMaterials.add( ShellMaterial( mat->GetSubMtl( face.getMatID() % mat->NumSubMtls() ), bakedmtl ) );
					} else
						usedMaterials.add( ShellMaterial( mat, bakedmtl ) );
				}
				else if ( material->NumSubMtls() > 0 ) // Multi-material without baked material 
				{  
					usedMaterials.add( ShellMaterial( material->GetSubMtl( face.getMatID() % material->NumSubMtls() ), 0 ) ); 
				}
				else	// Single material without baked material
				{
					usedMaterials.add( ShellMaterial( material, 0 ) );
				}				
			}
			std::sort( usedMaterials.begin(), usedMaterials.end() );
			usedMaterials.setSize( std::unique( usedMaterials.begin(), usedMaterials.end() ) - usedMaterials.begin() );
		}

		// create used materials
		for ( int mi = 0 ; mi < usedMaterials.size() ; ++mi )
		{
			ShellMaterial shellmtl = usedMaterials[mi];
			gm->materials.add( GmUtil::createGmMaterial( shellmtl.original, shellmtl.baked ) );
		}

		// add triangles
		for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi )
		{
			mb::Polygon* poly = gm->addPolygon();

			// triangle indices
			Face& face = mesh->faces[fi];
			for ( int vxi = 0 ; vxi < 3 ; ++vxi )
			{
				int vi = face.v[ vx[vxi] ];
				require( vi >= 0 && vi < gm->vertices() );
				mb::Vertex* vert = gm->getVertex( vi );
				poly->addVertex( vert );
			}

			// triangle material
			int polyMaterialIndex = 0;
			if ( material )
			{
				ShellMaterial mat( material, 0 );
				
				int numsubmaterials = material->NumSubMtls();  

				if ( numsubmaterials > 0 )
				{
					mat.original = material->GetSubMtl( face.getMatID() % material->NumSubMtls() );
		
					for ( int j = 0; j < numsubmaterials; ++j) // Is baked material present?
					{
						TSTR name = material->GetSubMtlSlotName(j);
						if ( strcmp( name, "Baked Material" ) == 0 )
							mat.baked = material->GetSubMtl( j );
						if ( strcmp( name, "Original Material" ) == 0 )
							mat.original = material->GetSubMtl( j );
					}
					if ( mat.original->NumSubMtls() > 0 )  // Is there a nested multi-material?
					{
						mat.original = mat.original->GetSubMtl( face.getMatID() % mat.original->NumSubMtls() );
					}
				}

				for ( int mi = 0 ; mi < usedMaterials.size() ; ++mi )
				{
					if ( usedMaterials[mi] == mat )
					{
						polyMaterialIndex = mi;
						break;
					}
				}
			}
			poly->setMaterial( polyMaterialIndex );
		}

		// add vertex colors
		int mp = 0;
		if ( mesh->mapSupport(mp) && mesh->getNumMapVerts(mp) > 0 )
		{
			mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 3, "rgb", mb::VertexMapFormat::VERTEXMAP_RGB );

			int tverts = mesh->getNumMapVerts( mp );
			UVVert* tvert = mesh->mapVerts( mp );
			TVFace* tface = mesh->mapFaces( mp );

			//Debug::println( "Vertex colors:" );
			for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi )
			{
				Face& face = mesh->faces[fi];
				mb::Polygon* poly = gm->getPolygon( fi );

				for ( int vxi = 0 ; vxi < 3 ; ++vxi )
				{
					int vi = face.v[ vx[vxi] ];
					mb::Vertex* vert = gm->getVertex( vi );
					Point3 tc = tvert[ tface[fi].t[ vx[vxi] ] % tverts ];
					float rgb[3] = {tc.x, tc.y, tc.z};
					vmad->addValue( vert->index(), poly->index(), rgb, 3 );
					//Debug::println( "  vertex[{0}].rgb: {1} {2} {3}", vert->index(), rgb[0], rgb[1], rgb[2] );
				}
			}
		}

		// add texcoord layers
		int lastCoords = MAX_MESHMAPS-2;
		while ( lastCoords > 0 && (!mesh->mapSupport(lastCoords) || 0 == mesh->getNumMapVerts(lastCoords)) )
			--lastCoords;
		if ( lastCoords > 8 )
			throw IOException( Format("Too many texture coordinate sets ({1}) in {0}", gm->name, lastCoords) );

		for ( mp = 1 ; mp <= lastCoords ; ++mp )
		{
			mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 2, "uv", mb::VertexMapFormat::VERTEXMAP_TEXCOORD );

			if ( mesh->mapSupport(mp) && mesh->getNumMapVerts(mp) > 0 )
			{
				int tverts = mesh->getNumMapVerts( mp );
				UVVert* tvert = mesh->mapVerts( mp );
				TVFace* tface = mesh->mapFaces( mp );
				
				for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi )
				{
					Face& face = mesh->faces[fi];
					mb::Polygon* poly = gm->getPolygon( fi );

					for ( int vxi = 0 ; vxi < 3 ; ++vxi )
					{
						int vi = face.v[ vx[vxi] ];
						mb::Vertex* vert = gm->getVertex( vi );
						Point3 tc = tvert[ tface[fi].t[ vx[vxi] ] % tverts ];
						float uv[2] = {tc.x, 1.f-tc.y};
						vmad->addValue( vert->index(), poly->index(), uv, 2 );
					}
				}
			}
		}

		// compute face vertex normals from smoothing groups
		require( mesh->getNumFaces() == gm->polygons() );
		mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 3, "vnormals", mb::VertexMapFormat::VERTEXMAP_NORMALS );
		for ( int fi = 0 ; fi < gm->polygons() ; ++fi )
		{
			mb::Polygon* poly = gm->getPolygon( fi );
			require( poly );
			require( poly->index() >= 0 && poly->index() < mesh->getNumFaces() );
			Face& face = mesh->faces[ poly->index() ];

			require( poly->vertices() == 3 );
			for ( int j = 0 ; j < poly->vertices() ; ++j )
			{
				Vector3 vn(0,0,0);
				mb::Vertex* vert = poly->getVertex( j );

				// sum influencing normals
				for ( int k = 0 ; k < vert->polygons() ; ++k )
				{
					mb::Polygon* vpoly = vert->getPolygon( k );
					require( vpoly );
					require( vpoly->index() >= 0 && vpoly->index() < mesh->getNumFaces() );
					Face& vface = mesh->faces[ vpoly->index() ];

					if ( 0 != (face.smGroup & vface.smGroup) || poly == vpoly )
					{
						Vector3 vpolyn;
						vpoly->getNormal( &vpolyn.x, &vpolyn.y, &vpolyn.z );
						vn += vpolyn;
					}
				}

				// normalize
				float lensqr = vn.lengthSquared();
				if ( lensqr > Float::MIN_VALUE )
					vn *= 1.f / Math::sqrt(lensqr);
				else
					vn = Vector3(0,0,0);

				vmad->addValue( vert->index(), poly->index(), vn.begin(), 3 );
			}
		}

		// re-export mesh points in non-deformed pose if Skin modifier present
		// NOTE: 3ds Mesh must not be used after this, because collapsing can invalidate it
		if ( skin )
		{
			// evaluate derived object before Skin modifier
			TimeValue time = 0;
			bool evalNext = false;
			bool evalDone = false;
			::ObjectState os;
			::Object* obj = node->GetObjectRef();
			while ( obj->SuperClassID() == GEN_DERIVOB_CLASS_ID && !evalDone )
			{
				IDerivedObject* derivedObj = static_cast<IDerivedObject*>(obj);
				for ( int modStack = 0 ; modStack < derivedObj->NumModifiers() ; ++modStack )
				{
					if ( evalNext )
					{
						os = derivedObj->Eval( time, modStack );
						evalDone = true;
						break;
					}

					Modifier* mod = derivedObj->GetModifier(modStack);
					if ( mod->ClassID() == SKIN_CLASSID )
						evalNext = true;
				}
				obj = derivedObj->GetObjRef();
			}

			// evaluate possible non-derived object
			if ( evalNext && !evalDone )
			{
				os = obj->Eval( time );
				evalDone = true;
			}

			// convert to TriObject and get points
			if ( evalDone && os.obj->CanConvertToType( Class_ID(TRIOBJ_CLASS_ID,0) ) )
			{
				Debug::println( "  Evaluating object {0} before Skin modifier", nodeName );

				// get TriObject
				std::auto_ptr<TriObject> triAutoDel(0);
				TriObject* tri = static_cast<TriObject*>( os.obj->ConvertToType( time, Class_ID(TRIOBJ_CLASS_ID,0) ) );
				if ( tri != os.obj )
					triAutoDel = std::auto_ptr<TriObject>( tri );

				// get mesh points before Skin is applied
				//Debug::println( "  Original collapsed mesh has {0} points, before Skin modifier {1} points", mesh->getNumVerts(), tri->mesh.getNumVerts() );
				require( gm->vertices() == tri->mesh.getNumVerts() );
				Mesh* mesh = &tri->mesh;
				int vertices = mesh->getNumVerts();
				for ( int vi = 0 ; vi < vertices ; ++vi )
				{
					Point3 v = vertexTM * mesh->verts[vi];
					mb::Vertex* vert = gm->getVertex( vi );
					vert->setPosition( v.x, v.y, v.z );
				}
			}
		}

		// split vertices with discontinuous vertex map values
		for ( int vmi = 0 ; vmi < gm->discontinuousVertexMaps() ; ++vmi )
		{
			mb::DiscontinuousVertexMap* vmad = gm->getDiscontinuousVertexMap( vmi );
			gm->splitVertexDiscontinuities( vmad );
		}

		// find base texcoord layer
		mb::DiscontinuousVertexMap* texcoords = 0;
		for ( int i = 0 ; i < gm->discontinuousVertexMaps() ; ++i )
		{
			mb::DiscontinuousVertexMap* vmad = gm->getDiscontinuousVertexMap(i);
			if ( vmad->dimensions() == 2 && vmad->format() == mb::VertexMapFormat::VERTEXMAP_TEXCOORD )
			{
				texcoords = vmad;
				break;
			}
		}
		if ( !texcoords )
			Debug::printlnError( "Object {0} must have texture coordinates", gm->name );
			// requires identification of footsteps in MySceneExport::isExportableGeometry
			//throw IOException( Format("Object {0} must have texture coordinates", gm->name) );

		// optimize
		gm->removeUnusedVertices();

		// cleanup export interfaces
#ifdef SGEXPORT_PHYSIQUE
		if ( mcExport )
		{
			require( phyExport );
			phyExport->ReleaseContextInterface( mcExport );
			mcExport = 0;
		}
		if ( phyExport )
		{
			require( phyMod );
			phyMod->ReleaseInterface( I_PHYINTERFACE, phyExport );
			phyExport = 0;
		}
#endif // SGEXPORT_PHYSIQUE
		if ( skin )
		{
			skinMod->ReleaseInterface( I_SKIN, skin );
			skin = 0;
			skinMod = 0;
		}
	}
	catch ( ... )
	{
		// cleanup export interfaces
#ifdef SGEXPORT_PHYSIQUE
		if ( mcExport )
		{
			require( phyExport );
			phyExport->ReleaseContextInterface( mcExport );
			mcExport = 0;
		}
		if ( phyExport )
		{
			require( phyMod );
			phyMod->ReleaseInterface( I_PHYINTERFACE, phyExport );
			phyExport = 0;
		}
#endif // SGEXPORT_PHYSIQUE
		if ( skin )
		{
			skinMod->ReleaseInterface( I_SKIN, skin );
			skin = 0;
			skinMod = 0;
		}
		throw;
	}
}
Example #13
0
INT_PTR CALLBACK BindProc(
		HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
	M3Mat *mp = (M3Mat*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
	if (!mp && msg!=WM_INITDIALOG) return FALSE;

	int id = LOWORD(wParam);
	int notify = HIWORD(wParam);


	switch (msg) {
		case WM_INITDIALOG:{
			mp = (M3Mat*)lParam;
			SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)mp);

			HWND modList = GetDlgItem(hWnd,IDC_MODLIST);

			SendMessage(modList,LB_RESETCONTENT,0,0);

			POINT lpPt; GetCursorPos(&lpPt);
			SetWindowPos(hWnd, NULL, lpPt.x, lpPt.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

			Object *pObj = mp->Wnode->GetObjectRef();
			IDerivedObject *pDerObj = NULL;
			Modifier *pMod = NULL;

			if( pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID) 
			{
				pDerObj = (IDerivedObject *) pObj;

				for(int i = 0 ; i < pDerObj->NumModifiers() ; i++ )
				{
					pMod = pDerObj->GetModifier(i);	
					SendMessage(modList,LB_ADDSTRING,0,(LPARAM) (LPCTSTR) pMod->GetName());
				}
			}

			SendMessage(modList,LB_SETCURSEL ,(WPARAM)-1,0);

			break;}


		case WM_COMMAND:

			if (notify==LBN_SELCHANGE){
				if(id==IDC_MODLIST){
					int mkSel = SendMessage(GetDlgItem(hWnd, IDC_MODLIST), LB_GETCURSEL, 0, 0);
					if(mkSel>=0){

						Object *pObj = mp->Wnode->GetObjectRef();
						IDerivedObject *pDerObj = NULL;
						Modifier *pMod = NULL;

						if( pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID) 
						{
							pDerObj = (IDerivedObject *) pObj;
							pMod = pDerObj->GetModifier(mkSel);	
							if(pMod->ClassID() == MR3_CLASS_ID) EnableWindow(GetDlgItem(hWnd,IDOK),TRUE);
							else EnableWindow(GetDlgItem(hWnd,IDOK),FALSE);
						}


					}
				}
			}

			switch (id) {
				case IDOK:
				{
					int mkSel = SendMessage(GetDlgItem(hWnd, IDC_MODLIST), LB_GETCURSEL, 0, 0);
					if(mkSel>=0){

						Object *pObj = mp->Wnode->GetObjectRef();
						IDerivedObject *pDerObj = NULL;
						Modifier *pMod = NULL;

						if( pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID) 
						{
							pDerObj = (IDerivedObject *) pObj;
							pMod = pDerObj->GetModifier(mkSel);	
							
							MorphR3 *mod = (MorphR3*)pMod;
							if(mod->CheckMaterialDependency() ) {
								EndDialog(hWnd,1);return TRUE;
							}

							// Make sure the node does not depend on us
							mod->BeginDependencyTest();
							mp->NotifyDependents(FOREVER,0,REFMSG_TEST_DEPENDENCY);
							if (mod->EndDependencyTest()) { 
								// display cyclic warning
								//
								if (GetCOREInterface()->GetQuietMode()) {
									TSTR cyclic;
									cyclic = GetString(IDS_CANNOT_BIND);
									GetCOREInterface()->Log()->LogEntry(SYSLOG_WARN,NO_DIALOG,GetString(IDS_CLASS_NAME),cyclic);
								}
								else
								{
									TSTR cyclic;
									cyclic = GetString(IDS_CANNOT_BIND);
									MessageBox(hWnd,cyclic,GetString(IDS_CLASS_NAME),MB_OK);
								}
								EndDialog(hWnd,1);
								return TRUE; 
							}

							if(mod) mod->morphmaterial = mp;

							mp->ReplaceReference(102, mod);
							mp->obName = mp->Wnode->GetName();

							mp->morphp = mod;
							if (mp->matDlg ){
								mp->matDlg->UpdateMorphInfo(UD_LINK);
								mp->matDlg->ReloadDialog();
							}
						}


					}
				}
				case IDCANCEL:
					EndDialog(hWnd,1);
				break;
				}
			break;
		
		

		default:
			return FALSE;
		}
	return TRUE;
	}
void SkeletonExporter::export_particle_spray(INode *node)
{
  char sval[50];
  Interval range = ip->GetAnimRange();
  ObjectState os = node->EvalWorldState(0);
  if (!os.obj) return;

  SimpleParticle *partsys;
  Object *p; IDerivedObject *q; Modifier *m;
  partsys=(SimpleParticle *)os.obj;
  Point3 row;
  Matrix3 mat;
  Mtl *materiale;
  INode *padre=node->GetParentNode();
  int mod_names=0, k, mod_count=0;
  char modNames[25][50], refname[50];
  int sf, sm, mf, n;

  if ((padre) && (strcmp(padre->GetName(), "Scene Root")!=0))
    sf=strlen(padre->GetName())+1;
  else sf=0;
  
  materiale=node->GetMtl();
  if (materiale) sm=strlen(materiale->GetName())+1;
  else sm=0;

  mf=0;

  // trovo i modificatori Wind e Gravity con il loro
  // nome
  p=node->GetObjOrWSMRef();
  if ((p->SuperClassID()==GEN_DERIVOB_CLASS_ID) &&
	 (p->ClassID()==Class_ID(WSM_DERIVOB_CLASS_ID, 0)))
  {
	q=(IDerivedObject *)p;
	n=q->NumModifiers();
	mod_names=mod_count=0;
	for (k=0; k<n; k++)
	{
      m=q->GetModifier(k);
      Class_ID cidd = m->ClassID();
	  if ((cidd==Class_ID(WINDMOD_CLASS_ID, 0)) ||
		  (cidd==Class_ID(GRAVITYMOD_CLASS_ID, 0)) ||
		  (cidd==Class_ID(BOMB_OBJECT_CLASS_ID, 0)))
	  {
		 SimpleWSMMod *wm=(SimpleWSMMod *)m;
		 strcpy(refname, wm->nodeRef->GetName());
		 strcpy(modNames[mod_count], refname);
		 mod_names+=(strlen(refname)+1);
         mod_count++;
	  }
	}
  }

  write_chunk_header(fA3D, SPRAY_PARTICLE_SYSTEM_ID, node->GetName(),
	                 4+sf+4+sm+  // padre, materiale
					 12+48+  //pivot, matrice world(t=0)
					 4+mf+   // nome mesh/oggetto
					 4+4+4+4+ // emitter: width, height, speed , variation
					 4+4+4+4+ // life, startTime, stopTime, max_particles
					 4+mod_names // num WSM, nomi WSM
					 );

  fprintf(fTXT, "Spray particle system found\n");
  fprintf(fTXT, "Name : %s\n", node->GetName());
  if (padre) fprintf(fTXT, "Parent name : %s\n", node->GetParentNode()->GetName());
  if (materiale) fprintf(fTXT, "Material name : %s\n", materiale->GetName());
  if (makeADP)
    fprintf(fADP, "  particle %c%s%c\n  {\n", '"', node->GetName(), '"');

  // -----------    scrivo il padre (flag, nome)   ------------------
  fwrite(&sf, sizeof(int), 1, fA3D);
  if (sf>0)
  {
	 write_string0(fA3D, padre->GetName());
	 if (makeADP) fprintf(fADP, "     father=%c%s%c;\n", '"', padre->GetName(), '"');
  }
  else
	 if (makeADP) fprintf(fADP, "     father=%cNONE%c;\n", '"', '"');


  // ---------   scrivo il materiale di base (flag, nome)   ----------
  fwrite(&sm, sizeof(int), 1, fA3D);
  if (sm>0)
  {
     write_string0(fA3D, materiale->GetName());
	 //if (makeADP) fprintf(fADP, "     material=%c%s%c;\n", '"', materiale->GetName(), '"');
  }
  else
	 //if (makeADP) fprintf(fADP, "     material=%cNONE%c;\n", '"', '"');


  // ---------------   scrittura del punto di pivot   ----------------
  GetPivotOffset(node, &row);
  fprintf(fTXT, "Pivot point : %f, %f, %f\n", row.x, row.y, row.z);
  write_point3(&row, fA3D);

  // -------------------   scrittura matrice   -----------------------
  mat = node->GetNodeTM(0);
  write_matrix(&mat, fA3D);

  // ---------   scrittura dell'eventuale nome della mesh   ----------
  fwrite(&mf, sizeof(int), 1, fA3D);
  if (mf>0)
  {
    write_string0(fA3D, "TO_DO");
    if (makeADP) fprintf(fADP, "    lod=%cTO_DO, 0, 99999.99%c;\n", '"', '"');
  }


  // *************  ESPORAZIONE DATI DEL PARTCLE SYSTEM  *************
  float initVel, var, width, height;
  int count, life, start_time, stop_time;

  partsys->pblock->GetValue(PB_EMITTERWIDTH, 0, width, FOREVER);
  partsys->pblock->GetValue(PB_EMITTERHEIGHT, 0, height, FOREVER);
  partsys->pblock->GetValue(PB_SPEED, 0, initVel, FOREVER);
  partsys->pblock->GetValue(PB_VARIATION, 0, var, FOREVER);
  partsys->pblock->GetValue(PB_LIFETIME, 0, life, FOREVER);
  life=life/ GetTicksPerFrame();
  partsys->pblock->GetValue(PB_STARTTIME, 0, start_time, FOREVER);
  start_time=start_time / GetTicksPerFrame();
  stop_time=range.End() / GetTicksPerFrame();
  partsys->pblock->GetValue(PB_RNDPARTICLES, 0, count, FOREVER);

  fprintf(fTXT, "Emitter width: %f\n", width);
  fprintf(fTXT, "Emitter height: %f\n", height);
  fprintf(fTXT, "Emitter speed (init vel): %f\n", initVel);
  fprintf(fTXT, "Emitter variation: %f\n", var);
  fprintf(fTXT, "Life: %d\n", life);
  fprintf(fTXT, "Start time: %d\n", start_time);
  fprintf(fTXT, "Stop time: %d\n", stop_time);
  fprintf(fTXT, "Max particles: %d\n", count);

  // informazioni in formato binario (.A3D)
  fwrite(&width, sizeof(float), 1, fA3D);
  fwrite(&height, sizeof(float), 1, fA3D);
  fwrite(&initVel, sizeof(float), 1, fA3D);
  fwrite(&var, sizeof(float), 1, fA3D);
  fwrite(&life, sizeof(int), 1, fA3D);
  fwrite(&start_time, sizeof(int), 1, fA3D);
  fwrite(&stop_time, sizeof(int), 1, fA3D);
  fwrite(&count, sizeof(int), 1, fA3D);

  fwrite(&mod_count, sizeof(int), 1, fA3D);
  fprintf(fTXT, "Modificatori (wind, gravity, bomb) collegati: %d\n", mod_count);
  for (k=0; k<mod_count; k++)
  {
     fprintf(fTXT, "Modificatore %d: %s\n", k, modNames[k]);
	 write_string0(fA3D, modNames[k]);
	 //if (makeADP)
       //fprintf(fADP, "     modifier=%c%s, ON%c;\n", '"', modNames[k], '"');
  }


  //------------------------
  // ESPORTAZIONE KEYFRAMER
  //------------------------
  Control *c;
  int size_key;

  // NB: per gli oggetti mesh e quant'altre tipologie di
  // oggetti che possono essere linkati (ovvero dove e'
  // possibile implmenetare gerarchie), esporto SEMPRE una key 
  // di posizione, una di rotazione ed una di scaling
  // POSITION CONTROLLER
  c=node->GetTMController()->GetPositionController();
  if ((c) && (c->NumKeys()>0))
  {
	 if (IsTCBControl(c)) size_key=36;
	 else
	 if (IsBezierControl(c)) size_key=40;
	 else size_key=16;
	 fprintf(fTXT, "Particle position track present.\n");
     write_chunk_header(fA3D, POSITION_TRACK_ID,
	                    node->GetName(), 1+2+4+c->NumKeys()*size_key);
     export_point3_track(c, 1, fA3D);
  }
  else
  {
	fprintf(fTXT, "Particle position track present. (1 key case)\n");
	if (!c) 	fprintf(fTXT, "c nullo !\n");
    fflush(fTXT);
	size_key=36;
    write_chunk_header(fA3D, POSITION_TRACK_ID,
	                   node->GetName(), 1+2+4+1*size_key);
    export_1key_point3_track(c, 1, fA3D);
  }


  // ROTATION CONTROLLER
  c=node->GetTMController()->GetRotationController();
  if ((c) && (c->NumKeys()>0))
  {
	 if (IsTCBControl(c)) size_key=40;
	 else size_key=20;
	 fprintf(fTXT, "Particle rotation track present.\n");
     write_chunk_header(fA3D, ROTATION_TRACK_ID,
	                    node->GetName(), 1+2+4+c->NumKeys()*size_key);
     export_rot_track(c, fA3D);
  }
  else
  {
	fprintf(fTXT, "Particle rotation track present. (1 key case)\n");
    fflush(fTXT);
	size_key=40;
    write_chunk_header(fA3D, ROTATION_TRACK_ID,
	                   node->GetName(), 1+2+4+1*size_key);
    export_1key_rot_track(c, fA3D);
  }

  
  // SCALE CONTROLLER
  c=node->GetTMController()->GetScaleController();
  if ((c) && (c->NumKeys()>0))
  {
	 if (IsTCBControl(c)) size_key=36;
	 else
	 if (IsBezierControl(c)) size_key=40;
	 else size_key=16;
	 fprintf(fTXT, "Particle scaling track present.\n");
     write_chunk_header(fA3D, SCALE_TRACK_ID,
	                    node->GetName(), 1+2+4+c->NumKeys()*size_key);
     export_scale_track(c, fA3D);
  }
  else
  {
	fprintf(fTXT, "Particle scaling track present. (1 key case)\n");
	size_key=36;
    write_chunk_header(fA3D, SCALE_TRACK_ID,
	                   node->GetName(), 1+2+4+1*size_key);
    export_1key_scale_track(c, fA3D);
  }

  // keyframer emitter width
  c=partsys->pblock->GetController(PB_EMITTERWIDTH);
  if ((c) && (c->NumKeys()>0))
  {
	 if (IsTCBControl(c)) size_key=28;
	 else
	 if (IsBezierControl(c)) size_key=16;
	 else size_key=8;
	 fprintf(fTXT, "Particle emitter width track present.\n");
     write_chunk_header(fA3D, PARTICLE_EMITTER_WIDTH_TRACK_ID,
	                    node->GetName(), 1+2+4+c->NumKeys()*size_key);
     export_float_track(c, 1, fA3D);
  }

  // keyframer emitter length
  c=partsys->pblock->GetController(PB_EMITTERHEIGHT);
  if ((c) && (c->NumKeys()>0))
  {
	 if (IsTCBControl(c)) size_key=28;
	 else
	 if (IsBezierControl(c)) size_key=16;
	 else size_key=8;
	 fprintf(fTXT, "Particle emitter length track present.\n");
     write_chunk_header(fA3D, PARTICLE_EMITTER_LENGTH_TRACK_ID,
	                    node->GetName(), 1+2+4+c->NumKeys()*size_key);
     export_float_track(c, 1, fA3D);
  }

  // keyframer particles speed
  c=partsys->pblock->GetController(PB_SPEED);
  if ((c) && (c->NumKeys()>0))
  {
	 if (IsTCBControl(c)) size_key=28;
	 else
	 if (IsBezierControl(c)) size_key=16;
	 else size_key=8;
	 fprintf(fTXT, "Particle emitter speed track present.\n");
     write_chunk_header(fA3D, PARTICLE_EMITTER_SPEED_TRACK_ID,
	                    node->GetName(), 1+2+4+c->NumKeys()*size_key);
     export_float_track(c, 1, fA3D);
  }

  // keyframer particles variations
  c=partsys->pblock->GetController(PB_VARIATION);
  if ((c) && (c->NumKeys()>0))
  {
	 if (IsTCBControl(c)) size_key=28;
	 else
	 if (IsBezierControl(c)) size_key=16;
	 else size_key=8;
	 fprintf(fTXT, "Particle emitter variation track present.\n");
     write_chunk_header(fA3D, PARTICLE_EMITTER_VARIATION_TRACK_ID,
	                    node->GetName(), 1+2+4+c->NumKeys()*size_key);
     export_float_track(c, 1, fA3D);
  }


  if (makeADP)
  {
    fprintf(fADP, "     texture=%cNONE%c;\n", '"', '"');
	my_ftoa(width, sval);
	fprintf(fADP, "     emitter_width=%c%s%c;\n", '"', sval, '"');
	my_ftoa(height, sval);
    fprintf(fADP, "     emitter_height=%c%s%c;\n", '"', sval, '"');
    fprintf(fADP, "     faded_particles=%cOFF%c;\n", '"', '"');
    fprintf(fADP, "     max_particles=%c%d%c;\n", '"', count, '"');
    fprintf(fADP, "     start_time=%c%d%c;\n", '"', start_time, '"');
    fprintf(fADP, "     end_time=%c%d%c;\n", '"', stop_time, '"');
    fprintf(fADP, "     life=%c%d%c;\n", '"', life, '"');
	my_ftoa(initVel, sval);
    fprintf(fADP, "     speed=%c%s%c;\n", '"', sval, '"');
	my_ftoa(var, sval);
    fprintf(fADP, "     variation=%c%s%c;\n", '"', sval, '"');
    fprintf(fADP, "     size_attenuation=%c0.4, 1.0, 0.8, 0.1%c;\n", '"', '"');
	fprintf(fADP, "  }\n\n");
  }
  fprintf(fTXT, "\n\n");
}
void HavokExport::makeHavokRigidBody(NiNodeRef parent, INode *ragdollParent, float scale) {

	this->scale = scale;

	Object *Obj = ragdollParent->GetObjectRef();

	Modifier* rbMod = nullptr;
	Modifier* shapeMod = nullptr;
	Modifier* constraintMod = nullptr;

	SimpleObject* havokTaperCapsule = nullptr;

	//get modifiers
	

	while (Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID) {
		IDerivedObject *DerObj = static_cast<IDerivedObject *> (Obj);
		const int nMods = DerObj->NumModifiers(); //it is really the last modifier on the stack, and not the total number of modifiers

		for (int i = 0; i < nMods; i++)
		{
			Modifier *Mod = DerObj->GetModifier(i);
			if (Mod->ClassID() == HK_RIGIDBODY_MODIFIER_CLASS_ID) {
				rbMod = Mod;
			}
			if (Mod->ClassID() == HK_SHAPE_MODIFIER_CLASS_ID) {
				shapeMod = Mod;
			}
			if (Mod->ClassID() == HK_CONSTRAINT_RAGDOLL_CLASS_ID || Mod->ClassID() == HK_CONSTRAINT_HINGE_CLASS_ID) {
				constraintMod = Mod;
			}
		}
		if (Obj->SuperClassID() == GEOMOBJECT_CLASS_ID) {
			havokTaperCapsule = (SimpleObject*)Obj;
		}
		Obj = DerObj->GetObjRef();
	}

	
	if (!rbMod) {
		throw exception(FormatText("No havok rigid body modifier found on %s", ragdollParent->GetName()));
	}
	if (!shapeMod) {
		throw exception(FormatText("No havok shape modifier found on %s", ragdollParent->GetName()));
	}

//	Object* taper = ragdollParent->GetObjectRef();
	IParamBlock2* taperParameters = Obj->GetParamBlockByID(PB_TAPEREDCAPSULE_OBJ_PBLOCK);
	float radius;
	enum
	{
		// GENERAL PROPERTIES ROLLOUT
		PA_TAPEREDCAPSULE_OBJ_RADIUS = 0,
		PA_TAPEREDCAPSULE_OBJ_TAPER,
		PA_TAPEREDCAPSULE_OBJ_HEIGHT,
		PA_TAPEREDCAPSULE_OBJ_VERSION_INTERNAL,
	};
	taperParameters->GetValue(PA_TAPEREDCAPSULE_OBJ_RADIUS, 0, radius, FOREVER);
	

	int shapeType;
	if (IParamBlock2* shapeParameters = shapeMod->GetParamBlockByID(PB_SHAPE_MOD_PBLOCK)) {
		shapeParameters->GetValue(PA_SHAPE_MOD_SHAPE_TYPE,0,shapeType,FOREVER);
	}

	//Havok Shape
	bhkShapeRef shape;

	if (shapeType == 2) {

		// Capsule
		bhkCapsuleShapeRef capsule = new bhkCapsuleShape();
		capsule->SetRadius(radius/scale);
		capsule->SetRadius1(radius/scale);
		capsule->SetRadius2(radius/scale);
		float length; 
		taperParameters->GetValue(PA_TAPEREDCAPSULE_OBJ_HEIGHT, 0, length, FOREVER);
		//get the normal
		Matrix3 axis(true);
		ragdollParent->GetObjOffsetRot().MakeMatrix(axis);
		Point3 normalAx = axis.GetRow(2);
		//capsule center
		Point3 center = ragdollParent->GetObjOffsetPos();
		//min and max points
		Point3 pt1 = center - normalAx*(length/2);
		Point3 pt2 = center + normalAx*(length/2);

		capsule->SetFirstPoint(TOVECTOR3(pt1)/scale);
		capsule->SetSecondPoint(TOVECTOR3(pt2)/scale);
		capsule->SetMaterial(HAV_MAT_SKIN);

		shape = StaticCast<bhkShape>(capsule);
		
	}
	else {
		// Sphere
		//CalcBoundingSphere(node, tm.GetTrans(), radius, 0);

		bhkSphereShapeRef sphere = new bhkSphereShape();
		sphere->SetRadius(radius/scale);
		sphere->SetMaterial(HAV_MAT_SKIN);
		shape = StaticCast<bhkShape>(sphere);
	}

	bhkRigidBodyRef body;

	if (shape)
	{
		bhkBlendCollisionObjectRef blendObj = new bhkBlendCollisionObject();
		body = new bhkRigidBody();

		Matrix3 tm = ragdollParent->GetObjTMAfterWSM(0);
		
		//Calculate Object Offset Matrix
		Matrix3 otm(1);
		Point3 pos = ragdollParent->GetObjOffsetPos();
		otm.PreTranslate(pos);
		Quat quat = ragdollParent->GetObjOffsetRot();
		PreRotateMatrix(otm, quat);
		Matrix3 otmInvert = otm;
		otmInvert.Invert();

		//correct object tm
		Matrix3 tmbhk = otmInvert * tm;

		//set geometric parameters
		body->SetRotation(TOQUATXYZW(Quat(tmbhk).Invert()));
		body->SetTranslation(TOVECTOR4(tmbhk.GetTrans() / scale));
		body->SetCenter(TOVECTOR4(ragdollParent->GetObjOffsetPos())/scale);

		//set physics
		if (IParamBlock2* rbParameters = rbMod->GetParamBlockByID(PB_RB_MOD_PBLOCK)) {
			//These are fundamental parameters

			int lyr = NP_DEFAULT_HVK_LAYER;
			int mtl = NP_DEFAULT_HVK_MATERIAL;
			int msys = NP_DEFAULT_HVK_MOTION_SYSTEM;
			int qtype = NP_DEFAULT_HVK_QUALITY_TYPE;
			float mass = NP_DEFAULT_HVK_MASS;
			float lindamp = NP_DEFAULT_HVK_LINEAR_DAMPING;
			float angdamp = NP_DEFAULT_HVK_ANGULAR_DAMPING;
			float frict = NP_DEFAULT_HVK_FRICTION;
			float maxlinvel = NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY;
			float maxangvel = NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY;
			float resti = NP_DEFAULT_HVK_RESTITUTION;
			float pendepth = NP_DEFAULT_HVK_PENETRATION_DEPTH;
			Point3 InertiaTensor;


			rbParameters->GetValue(PA_RB_MOD_MASS, 0, mass, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_RESTITUTION, 0, resti, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_FRICTION, 0, frict, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_INERTIA_TENSOR, 0, InertiaTensor, FOREVER);


			rbParameters->GetValue(PA_RB_MOD_LINEAR_DAMPING, 0, lindamp, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_CHANGE_ANGULAR_DAMPING, 0, angdamp, FOREVER);

			rbParameters->GetValue(PA_RB_MOD_MAX_LINEAR_VELOCITY, 0, maxlinvel, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_MAX_ANGULAR_VELOCITY, 0, maxangvel, FOREVER);

			rbParameters->GetValue(PA_RB_MOD_ALLOWED_PENETRATION_DEPTH, 0, pendepth, FOREVER);
			rbParameters->GetValue(PA_RB_MOD_QUALITY_TYPE, 0, qtype, FOREVER);

			body->SetMass(mass);
			body->SetRestitution(resti);
			body->SetFriction(frict);
			body->SetLinearDamping(lindamp);
			body->SetMaxLinearVelocity(maxlinvel);
			body->SetMaxAngularVelocity(maxangvel);
			body->SetPenetrationDepth(pendepth);
			InertiaMatrix im;
			im[0][0] = InertiaTensor[0];
			im[1][1] = InertiaTensor[1];
			im[2][2] = InertiaTensor[2];

			body->SetInertia(im);

			/*switch (qtype) {
			case QT_FIXED:
				body->SetQualityType(MO_QUAL_FIXED);
				break;
			case QT_KEYFRAMED:
				body->SetQualityType(MO_QUAL_KEYFRAMED);
				break;
			case QT_DEBRIS:
				body->SetQualityType(MO_QUAL_DEBRIS);
				break;
			case QT_MOVING:
				body->SetQualityType(MO_QUAL_MOVING);
				break;
			case QT_CRITICAL:
				body->SetQualityType(MO_QUAL_CRITICAL);
				break;
			case QT_BULLET:
				body->SetQualityType(MO_QUAL_BULLET);
				break;
			case QT_KEYFRAMED_REPORTING:
				body->SetQualityType(MO_QUAL_KEYFRAMED_REPORT);
				break;
			}*/

			body->SetSkyrimLayer(SkyrimLayer::SKYL_BIPED);
			body->SetSkyrimLayerCopy(SkyrimLayer::SKYL_BIPED);

			body->SetMotionSystem(MotionSystem::MO_SYS_BOX);
			body->SetDeactivatorType(DeactivatorType::DEACTIVATOR_NEVER);
			body->SetSolverDeactivation(SolverDeactivation::SOLVER_DEACTIVATION_LOW);
			body->SetQualityType(MO_QUAL_FIXED);

		}
		
		if (constraintMod && ragdollParent->GetParentNode() && parent->GetParent()) {
			if (constraintMod->ClassID() == HK_CONSTRAINT_RAGDOLL_CLASS_ID) {
				bhkRagdollConstraintRef ragdollConstraint = new bhkRagdollConstraint();
				
				//entities
				ragdollConstraint->AddEntity(body);
				NiNodeRef parentRef = parent->GetParent();
				bhkRigidBodyRef nifParentRigidBody;
				while (parentRef) {
					if (parentRef->GetCollisionObject()) {
						nifParentRigidBody = StaticCast<bhkRigidBody>(StaticCast<bhkBlendCollisionObject>(parentRef->GetCollisionObject())->GetBody());
						break;
					}
					parentRef = parentRef->GetParent();
				}
				if (!nifParentRigidBody)
					throw exception(FormatText("Unable to find NIF constraint parent for ragdoll node %s", ragdollParent->GetName()));
				ragdollConstraint->AddEntity(nifParentRigidBody);

				RagdollDescriptor desc;
				//parameters
				if (IParamBlock2* constraintParameters = constraintMod->GetParamBlockByID(PB_CONSTRAINT_MOD_COMMON_SPACES_PARAMS)) {
					Point3 pivotA;
					Matrix3 parentRotation;
					Point3 pivotB;
					Matrix3 childRotation;
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_CHILD_SPACE_TRANSLATION, 0, pivotB, FOREVER);
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_CHILD_SPACE_ROTATION, 0, childRotation, FOREVER);
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_PARENT_SPACE_TRANSLATION, 0, pivotA, FOREVER);
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_PARENT_SPACE_ROTATION, 0, parentRotation, FOREVER);
					
					desc.pivotA = TOVECTOR4(pivotA);
					desc.pivotB = TOVECTOR4(pivotB);
					desc.planeA = TOVECTOR4(parentRotation.GetRow(0));
					desc.motorA = TOVECTOR4(parentRotation.GetRow(1));
					desc.twistA = TOVECTOR4(parentRotation.GetRow(2));
					desc.planeB = TOVECTOR4(childRotation.GetRow(0));
					desc.motorB = TOVECTOR4(childRotation.GetRow(1));
					desc.twistB = TOVECTOR4(childRotation.GetRow(2));
					
				}
				if (IParamBlock2* constraintParameters = constraintMod->GetParamBlockByID(PB_RAGDOLL_MOD_PBLOCK)) {
					float coneMaxAngle;
					float planeMinAngle;
					float planeMaxAngle;
					float coneMinAngle;
					float twistMinAngle;
					float maxFriction;

					constraintParameters->GetValue(PA_RAGDOLL_MOD_CONE_ANGLE, 0, coneMaxAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_PLANE_MIN, 0, planeMinAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_PLANE_MAX, 0, planeMaxAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_TWIST_MIN, 0, coneMinAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_TWIST_MAX, 0, twistMinAngle, FOREVER);
					constraintParameters->GetValue(PA_RAGDOLL_MOD_MAX_FRICTION_TORQUE, 0, maxFriction, FOREVER);

					desc.coneMaxAngle = TORAD(coneMaxAngle);
					desc.planeMinAngle = TORAD(planeMinAngle);
					desc.planeMaxAngle = TORAD(planeMaxAngle);
					desc.coneMaxAngle = TORAD(coneMinAngle);
					desc.twistMinAngle = TORAD(twistMinAngle);
					desc.maxFriction = maxFriction;


				}
				ragdollConstraint->SetRagdoll(desc);
				body->AddConstraint(ragdollConstraint);
			}
			else if (constraintMod->ClassID() == HK_CONSTRAINT_HINGE_CLASS_ID) {
				bhkLimitedHingeConstraintRef limitedHingeConstraint = new bhkLimitedHingeConstraint();

				//entities
				limitedHingeConstraint->AddEntity(body);
				NiNodeRef parentRef = parent->GetParent();
				bhkRigidBodyRef nifParentRigidBody;
				while (parentRef) {
					if (parentRef->GetCollisionObject()) {
						nifParentRigidBody = StaticCast<bhkRigidBody>(StaticCast<bhkBlendCollisionObject>(parentRef->GetCollisionObject())->GetBody());
						break;
					}
					parentRef = parentRef->GetParent();
				}
				if (!nifParentRigidBody)
					throw exception(FormatText("Unable to find NIF constraint parent for limited hinge node %s", ragdollParent->GetName()));
				limitedHingeConstraint->AddEntity(nifParentRigidBody);

				LimitedHingeDescriptor lh;

				if (IParamBlock2* constraintParameters = constraintMod->GetParamBlockByID(PB_CONSTRAINT_MOD_COMMON_SPACES_PARAMS)) {
					Matrix3 parentRotation;
					Matrix3 childRotation;
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_CHILD_SPACE_ROTATION, 0, childRotation, FOREVER);
					constraintParameters->GetValue(PA_CONSTRAINT_MOD_PARENT_SPACE_ROTATION, 0, parentRotation, FOREVER);

					lh.perp2AxleInA1 = TOVECTOR4(parentRotation.GetRow(0));
					lh.perp2AxleInA2 = TOVECTOR4(parentRotation.GetRow(1));
					lh.axleA = TOVECTOR4(parentRotation.GetRow(2));
					lh.perp2AxleInB1 = TOVECTOR4(childRotation.GetRow(0));
					lh.perp2AxleInB2 = TOVECTOR4(childRotation.GetRow(1));
					lh.axleB = TOVECTOR4(childRotation.GetRow(2));
					
				}
				if (IParamBlock2* constraintParameters = constraintMod->GetParamBlockByID(PB_HINGE_MOD_PBLOCK)) {
					float minAngle;
					float maxAngle;
					float maxFriction;

					constraintParameters->GetValue(PA_HINGE_MOD_LIMIT_MIN, 0, minAngle, FOREVER);
					constraintParameters->GetValue(PA_HINGE_MOD_LIMIT_MAX, 0, maxAngle, FOREVER);
					constraintParameters->GetValue(PA_HINGE_MOD_MAX_FRICTION_TORQUE, 0, maxFriction, FOREVER);
					//	constraintParameters->SetValue(PA_HINGE_MOD_MOTOR_TYPE, 0, lh.motor., 0);

					lh.minAngle = TORAD(minAngle);
					lh.maxAngle = TORAD(maxAngle);
					lh.maxAngle = maxFriction;

				}
				limitedHingeConstraint->SetLimitedHinge(lh);
				body->AddConstraint(limitedHingeConstraint);
			}
		}


		//InitializeRigidBody(body, node);
		body->SetShape(shape);
		blendObj->SetBody(StaticCast<NiObject>(body));
		parent->SetCollisionObject(StaticCast<NiCollisionObject>(blendObj));
	}

	////rigid body parameters
	//	// get data from node
	//int lyr = NP_DEFAULT_HVK_LAYER;
	//int mtl = NP_DEFAULT_HVK_MATERIAL;
	//int msys = NP_DEFAULT_HVK_MOTION_SYSTEM;
	//int qtype = NP_DEFAULT_HVK_QUALITY_TYPE;
	//float mass = NP_DEFAULT_HVK_MASS;
	//float lindamp = NP_DEFAULT_HVK_LINEAR_DAMPING;
	//float angdamp = NP_DEFAULT_HVK_ANGULAR_DAMPING;
	//float frict = NP_DEFAULT_HVK_FRICTION;
	//float maxlinvel = NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY;
	//float maxangvel = NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY;
	//float resti = NP_DEFAULT_HVK_RESTITUTION;
	//float pendepth = NP_DEFAULT_HVK_PENETRATION_DEPTH;
	//BOOL transenable = TRUE;

	//if (IParamBlock2* rbParameters = rbMod->GetParamBlockByID(PB_SHAPE_MOD_PBLOCK))
	//{
	//	//These are fundamental parameters
	//	rbParameters->GetValue(PA_RB_MOD_MASS, 0, mass, FOREVER);
	//	rbParameters->GetValue(PA_RB_MOD_RESTITUTION, 0, resti, FOREVER);
	//	rbParameters->GetValue(PA_RB_MOD_FRICTION, 0, frict, FOREVER);

	//	rbParameters->GetValue(PA_RB_MOD_LINEAR_DAMPING, 0, lindamp, FOREVER);
	//	rbParameters->GetValue(PA_RB_MOD_CHANGE_ANGULAR_DAMPING, 0, angdamp, FOREVER);

	//	rbParameters->GetValue(PA_RB_MOD_MAX_LINEAR_VELOCITY, 0, maxlinvel, FOREVER);
	//	rbParameters->GetValue(PA_RB_MOD_MAX_ANGULAR_VELOCITY, 0, maxangvel, FOREVER);

	//	rbParameters->GetValue(PA_RB_MOD_ALLOWED_PENETRATION_DEPTH, 0, pendepth, FOREVER);

	//	rbParameters->GetValue(PA_RB_MOD_QUALITY_TYPE, 0, qtype, FOREVER);


	//	switch (qtype) {
	//	case MO_QUAL_INVALID:
	//		break;
	//	case QT_FIXED:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, MO_QUAL_FIXED, 0);
	//		break;
	//	case MO_QUAL_KEYFRAMED:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_KEYFRAMED, 0);
	//		break;
	//	case MO_QUAL_DEBRIS:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_DEBRIS, 0);
	//		break;
	//	case MO_QUAL_MOVING:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_MOVING, 0);
	//		break;
	//	case MO_QUAL_CRITICAL:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_CRITICAL, 0);
	//		break;
	//	case MO_QUAL_BULLET:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_BULLET, 0);
	//		break;
	//	case MO_QUAL_USER:
	//		break;
	//	case MO_QUAL_CHARACTER:
	//		break;
	//	case MO_QUAL_KEYFRAMED_REPORT:
	//		rbParameters->SetValue(PA_RB_MOD_QUALITY_TYPE, 0, QT_KEYFRAMED_REPORTING, 0);
	//		break;
	//	}

	//	// setup body
	//	bhkRigidBodyRef body = transenable ? new bhkRigidBodyT() : new bhkRigidBody();

	//	OblivionLayer obv_layer; SkyrimLayer sky_layer;
	//	GetHavokLayersFromIndex(lyr, (int*)&obv_layer, (int*)&sky_layer);
	//	body->SetLayer(obv_layer);
	//	body->SetLayerCopy(obv_layer);
	//	body->SetSkyrimLayer(sky_layer);

	//	body->SetMotionSystem(MotionSystem(msys));
	//	body->SetQualityType(MotionQuality(qtype));
	//	body->SetMass(mass);
	//	body->SetLinearDamping(lindamp);
	//	body->SetAngularDamping(angdamp);
	//	body->SetFriction(frict);
	//	body->SetRestitution(resti);
	//	body->SetMaxLinearVelocity(maxlinvel);
	//	body->SetMaxAngularVelocity(maxangvel);
	//	body->SetPenetrationDepth(pendepth);
	//	body->SetCenter(center);
	//	QuaternionXYZW q; q.x = q.y = q.z = 0; q.w = 1.0f;
	//	body->SetRotation(q);
	//}
}