Skip to content
Snippets Groups Projects
bhkRigidBodyModifer.cpp 19.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • #pragma warning( disable:4800 )
    
    #include <map>
    #include "NifProps.h"
    #include "NifStrings.h"
    #include "NifPlugins.h"
    #include "NifGui.h"
    #include "bhkRigidBodyInterface.h"
    
    Tazpn's avatar
    Tazpn committed
    #include "bhkHelperInterface.h"
    #include "bhkHelperFuncs.h"
    #include <MeshDelta.h>
    
    
    using namespace std;
    
    #define PBLOCK_REF	0
    
    Tazpn's avatar
    Tazpn committed
    Class_ID BHKRIGIDBODYMODIFIER_CLASS_ID = Class_ID(0x398fd801, 0x303e44e5);
    
    
    class bhkValidatorClass : public PBValidator
    {
    public:
       class bhkRigidBodyModifier *mod;
    private:
       BOOL Validate(PB2Value &v) 
       {
          INode *node = (INode*) v.r;
          if (node->TestForLoop(FOREVER,(ReferenceMaker *) mod)!=REF_SUCCEED) return FALSE;
    
          ObjectState os = node->EvalWorldState(0);
          //Allow only tri object derived objects
          if (os.obj->CanConvertToType(triObjectClassID)  && os.obj->SuperClassID() != SHAPE_CLASS_ID) {			
             return TRUE;
          }
          // and out objects which support the RigidBodyInterface
    
          if (os.obj->SuperClassID() == HELPER_CLASS_ID && NULL != GetInterface(BHKRIGIDBODYINTERFACE_DESC)) {
             return TRUE;
          }
    
          if (os.obj->SuperClassID() == HELPER_CLASS_ID && os.obj->ClassID().PartB() == BHKRIGIDBODYCLASS_DESC.PartB() ) {
             return TRUE;
          }
          return FALSE;
       };
    };
    
    
    Tazpn's avatar
    Tazpn committed
    class bhkRigidBodyModifier : public Modifier, public bhkHelperInterface
    
    {
    
    public:
    
    	bhkRigidBodyModifier();
    	~bhkRigidBodyModifier();		
    
       void DeleteThis() { delete this; }
       void GetClassName(TSTR& s) { s = "bhkRigidBodyModifier"; }  
       virtual Class_ID ClassID() { return BHKRIGIDBODYMODIFIER_CLASS_ID; }		
       RefTargetHandle Clone(RemapDir& remap);
       TCHAR *GetObjectName() { return "bhkRigidBodyModifier"; }
    
       // From modifier
    	ChannelMask ChannelsUsed()  {return PART_GEOM|PART_TOPO;}
    	ChannelMask ChannelsChanged() {return PART_GEOM;}
    //	ChannelMask ChannelsUsed()  { return 0; }
    //   ChannelMask ChannelsChanged() { return 0; }
       Class_ID InputType() { return mapObjectClassID; }
       void ModifyObject (TimeValue t, ModContext &mc, ObjectState *os, INode *node);
       Interval LocalValidity(TimeValue t) { return GetValidity(t); }
       Interval GetValidity (TimeValue t);
       BOOL DependOnTopology(ModContext &mc) { return TRUE; }
    	void NotifyInputChanged(Interval changeInt, PartID partID, RefMessage message, ModContext *mc);
    
       void BeginEditParams (IObjParam  *ip, ULONG flags,Animatable *prev);
       void EndEditParams (IObjParam *ip,ULONG flags,Animatable *next);		
    
    	int Display(TimeValue t, INode* inode, ViewExp *vpt, int flagst, ModContext *mc);
    
    
    Tazpn's avatar
    Tazpn committed
    	void BuildEmpty(Mesh& mesh);
    	void BuildColBox(Mesh& mesh);
    	void BuildColSphere(Mesh& mesh);
    	void BuildColCapsule(Mesh& mesh);
    	void BuildColStrips(Mesh& mesh);
    	void BuildColPackedStrips(Mesh& mesh);
    	void BuildColConvex(Mesh& mesh);
    
    	void BuildOptimize(Mesh& mesh);
    
    
    	void			SelectionSetChanged(Interface *ip,IUtil *iu);
    
    	void			selectionChanged();
       void        saveState();
    
       INT_PTR	dlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    
    
       // ParamBlock2 access:
       int NumParamBlocks () { return 1; }
       IParamBlock2* GetParamBlock(int i) 
       { 
          if (i == 0) return pblock;
          return NULL;
       }
       IParamBlock2* GetParamBlockByID(BlockID id) { 
          if (pblock->ID() == id) return pblock;
          return NULL; 
       }
    
       CreateMouseCallBack* GetCreateMouseCallBack() {return NULL;} 
    
       virtual	int NumRefs();
       virtual  RefTargetHandle GetReference(int i);
       virtual  void SetReference(int i, RefTargetHandle rtarg);
       virtual  RefResult   NotifyRefChanged(Interval,RefTargetHandle,PartID &,RefMessage);
    
       int NumSubs() {return 1;}
       Animatable* SubAnim(int i) { return GetReference(i); }
       TSTR SubAnimName(int i) {return GetString (IDS_PARAMS);}
    
       BOOL SetObject(INode *newNode);
       INode* GetObject();
    
    	void UpdateBVDialogs();
    
    
    Tazpn's avatar
    Tazpn committed
    	const Mesh* GetMesh() const
    	{
    		return &proxyMesh;
    	}
    
    	virtual BaseInterface *GetInterface(Interface_ID id)
    	{
    		if (id == BHKHELPERINTERFACE_DESC)
    			return (bhkHelperInterface*)this;
    		return Modifier::GetInterface(id);
    	}
    
    Tazpn's avatar
    Tazpn committed
    	void CreateMesh();
    
    
    Tazpn's avatar
    Tazpn committed
    public:
    
       StdMat2* collMat;
    
    Tazpn's avatar
    Tazpn committed
    	Mesh proxyMesh;
    
    
    	IParamBlock2 *pblock;
       IParamMap2 *pmapParam;
    	IParamMap2 *pbvParams[4]; //box, sphere, capsule, proxy
    
    	Interface		*mIP;
       Tab<INode*> mNodes;
    
       bhkValidatorClass validator;
    
    	void enableGUI(BOOL object, BOOL hvk, BOOL anim);		
    };
    
    extern ClassDesc2* GetbhkRigidBodyModifierDesc();
    static ParamBlockDesc2& get_havok_param_blk();
    
    class bhkRigidBodyModifierClassDesc : public ClassDesc2
    {
    	public:
       bhkRigidBodyModifierClassDesc() {
          get_havok_param_blk().SetClassDesc(this);
       }
    	int 			IsPublic() { return TRUE; }
    	void *			Create(BOOL loading = FALSE) { 
          return new bhkRigidBodyModifier();
       }
    	const TCHAR *	ClassName() { return GetString(IDS_RB_CLASS_NAME); }
    	SClass_ID		SuperClassID() { return OSM_CLASS_ID; }
    	Class_ID		ClassID() { return BHKRIGIDBODYMODIFIER_CLASS_ID; }
    	const TCHAR* 	Category() { return GetString(IDS_CATEGORY); }
    
    	const TCHAR*	InternalName() { return _T("bhkRigidBodyModifier"); }
    	HINSTANCE		HInstance() { return hInstance; }
    };
    
    
    
    // Parameter and ParamBlock IDs
    
    Tazpn's avatar
    Tazpn committed
    enum { havok_params, opt_params, clone_params};  // pblock ID
    
    enum { PB_BOUND_TYPE, PB_MATERIAL, PB_OPT_ENABLE, PB_MAXEDGE, PB_FACETHRESH, PB_EDGETHRESH, PB_BIAS, };
    
    
    enum { havok_params_panel, };
    
    
    Tazpn's avatar
    Tazpn committed
    enum { bv_type_none, bv_type_box, bv_type_sphere, bv_type_capsule, bv_type_shapes, bv_type_convex, };  // pblock ID
    
    
    static ParamBlockDesc2 havok_param_blk ( 
       havok_params, _T("BoundingVolumes"),  0, NULL, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, PBLOCK_REF,
       //rollout
    
    Tazpn's avatar
    Tazpn committed
        3,
    
    Tazpn's avatar
    Tazpn committed
        havok_params,	IDD_RB_MOD_PANEL,  IDS_PARAMS, 0, 0, NULL, 
    
    	opt_params,		IDD_RB_MOD_PANEL1, IDS_OPT_PARAMS, 0, 0, NULL,
    
    Tazpn's avatar
    Tazpn committed
    	clone_params,	IDD_CLONE_PANEL,   IDS_CLONE_PARAMS, 0, 0, NULL,
    
    Tazpn's avatar
    Tazpn committed
        PB_MATERIAL, _T("material"), TYPE_INT, P_ANIMATABLE,	IDS_DS_MATERIAL,
    
          p_default,	NP_DEFAULT_HVK_MATERIAL,
    
    Tazpn's avatar
    Tazpn committed
          end,
    
    Tazpn's avatar
    Tazpn committed
    	PB_BOUND_TYPE, 	_T("boundType"),	TYPE_INT, 0, IDS_BV_BOUNDING_TYPE,
    	  p_default, 		bv_type_shapes, 
    	  p_range, 		0, 5, 
    	  p_ui, 			havok_params,	TYPE_RADIO, 6, IDC_RDO_NO_COLL, IDC_RDO_AXIS_ALIGNED_BOX, IDC_RDO_SPHERE, IDC_RDO_CAPSULE, IDC_RDO_PROXY_MESH, IDC_RDO_CONVEX,
    	  end,
    
    	PB_OPT_ENABLE,	_T("enableOptimize"), TYPE_BOOL, 0, IDS_OPT_ENABLE,
    	  p_default, 	FALSE, 
    	  p_ui,			opt_params, TYPE_SINGLECHEKBOX, IDC_OPT_ENABLE,
    	  end,
      
    	PB_FACETHRESH,	_T("faceThresh"),	TYPE_FLOAT, P_RESET_DEFAULT, IDS_OPT_FACETHRESH,
    	  p_default, 	0.1f, 
    	  p_range, 		0.0f, 90.0f, 
    	  p_ui,			opt_params, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_OPT_FACETHRESH, IDC_OPT_FACETHRESHSPIN, 0.01f,
    	  p_uix,		opt_params,
    	  end,
    
    	PB_EDGETHRESH,		_T("edgeThresh"),		TYPE_FLOAT, 0, IDS_OPT_EDGETHRESH,
    	  p_default, 	0.1f, 
    	  p_range, 		0.0f, 90.0f, 
    	  p_ui,			opt_params, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_OPT_EDGETHRESH, IDC_OPT_EDGETHRESHSPIN, 0.01f,
    	  p_uix,		opt_params,
    	  end,
    
        PB_BIAS,		_T("bias"),		TYPE_FLOAT, 0, IDS_OPT_BIAS,
    	  p_default, 	0.1f, 
    	  p_range, 		0.0f, 1.0f, 
    	  p_ui,			opt_params, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_OPT_BIAS, IDC_OPT_BIASSPIN, 0.01f,
    	  p_uix,		opt_params,
    	  end,
    
    
       end,
       end
       );
    
    static bhkRigidBodyModifierClassDesc bhkRigidBodyModifierDesc;
    ClassDesc2* GetbhkRigidBodyModifierDesc() { return &bhkRigidBodyModifierDesc; }
    ParamBlockDesc2& get_havok_param_blk() {
       return havok_param_blk;
    }
    
    
    class bhkRigidBodyModifierDlgProc : public ParamMap2UserDlgProc {
    public:
       bhkRigidBodyModifier *mod;
    
    Tazpn's avatar
    Tazpn committed
       NpComboBox		mCbMaterial;
    
       bhkRigidBodyModifierDlgProc(bhkRigidBodyModifier* m) {mod = m;}		
    
       INT_PTR DlgProc(TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);		
    
       void DeleteThis() {delete this;}		
    };
    
    
    INT_PTR bhkRigidBodyModifierDlgProc::DlgProc (TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
    
    {
       switch (msg) 
       {
       case WM_INITDIALOG:
    
    Tazpn's avatar
    Tazpn committed
    	   {
    		   mCbMaterial.init(GetDlgItem(hWnd, IDC_CB_MATERIAL));
    		   for (const char **str = NpHvkMaterialNames; *str; ++str)
    			   mCbMaterial.add(*str);
    
    		   int sel = NP_DEFAULT_HVK_MATERIAL;
    		   Interval valid;
    		   mod->pblock->GetValue( PB_MATERIAL, 0, sel, valid);
    		   mCbMaterial.select( sel );
    
    		   EnableWindow(GetDlgItem(hWnd, IDC_RDO_CAPSULE), FALSE);
    
    Tazpn's avatar
    Tazpn committed
    
    		   Update(t);
    		   break;
    	   }
    
    
       case WM_DESTROY:
    
    Tazpn's avatar
    Tazpn committed
    	   break;
    
    
       case WM_COMMAND:
    
    Tazpn's avatar
    Tazpn committed
    	   switch (LOWORD(wParam))
    	   {
    	   case IDC_CB_MATERIAL:
    		   if (HIWORD(wParam)==CBN_SELCHANGE) {
    			   mod->pblock->SetValue( PB_MATERIAL, 0, mCbMaterial.selection() );
    		   }
    		   break;
    
    
    Tazpn's avatar
    Tazpn committed
    	   case IDC_BTN_CLONE:
    		   mod->CreateMesh();
    		   break;
    
    
    Tazpn's avatar
    Tazpn committed
    	   default:
    		   return FALSE;
    	   }
    
    Tazpn's avatar
    Tazpn committed
       return FALSE;
    
    Tazpn's avatar
    Tazpn committed
    namespace
    {
    	class CloneMeshDlgProc : public ParamMap2UserDlgProc {
    	public:
    		bhkRigidBodyModifier *mod;
    		CloneMeshDlgProc(bhkRigidBodyModifier* m) {mod = m;}		
    		INT_PTR DlgProc(TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);		
    		void DeleteThis() {delete this;}		
    	};
    
    	INT_PTR CloneMeshDlgProc::DlgProc (TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
    	{
    		switch (msg) 
    		{
    		case WM_COMMAND:
    			switch (LOWORD(wParam))
    			{
    			case IDC_BTN_CLONE:
    				mod->CreateMesh();
    				return TRUE;
    
    			default:
    				return FALSE;
    			}
    		}
    		return FALSE;
    	}
    }
    
    
    //--- bhkRigidBodyModifier -------------------------------------------------------
    
    bhkRigidBodyModifier::bhkRigidBodyModifier()
    {
    	mIP = NULL;	
    	pblock = NULL;
       pmapParam = NULL;
       validator.mod = this;
       bhkRigidBodyModifierDesc.MakeAutoParamBlocks(this);
    
       collMat = NewDefaultStdMat();
       collMat->SetDiffuse(Color(1.0f, 0.0f, 0.0f), 0);
       collMat->SetWire(TRUE);
    }
    
    bhkRigidBodyModifier::~bhkRigidBodyModifier()
    {
       havok_param_blk.SetUserDlgProc();
       if (pmapParam) {
          DestroyCPParamMap2 (pmapParam);
          pmapParam = NULL;
       }
    }
    
    RefTargetHandle bhkRigidBodyModifier::Clone(RemapDir& remap) {
       bhkRigidBodyModifier *mod = new bhkRigidBodyModifier();
       mod->ReplaceReference(0,remap.CloneRef(GetReference(0)));
       mod->ReplaceReference(1,remap.CloneRef(GetReference(1)));
       BaseClone(this, mod, remap);
       return mod;
    }
    
    
    int bhkRigidBodyModifier::NumRefs()
    {
    
    Tazpn's avatar
    Tazpn committed
       return 1;
    
    }
    
    RefTargetHandle bhkRigidBodyModifier::GetReference(int i)
    {
       if (i==0) return pblock;
       return NULL;
    }
    
    void bhkRigidBodyModifier::SetReference(int i, RefTargetHandle rtarg)
    {
       if (i==0) pblock = (IParamBlock2*)rtarg;
    }
    
    RefResult bhkRigidBodyModifier::NotifyRefChanged(
       Interval changeInt, 
       RefTargetHandle hTarget, 
       PartID& partID, 
       RefMessage message)
    {
       switch (message) 
       {
       case REFMSG_CHANGE:
          ParamID changing_param = pblock->LastNotifyParamID();
          havok_param_blk.InvalidateUI(changing_param);
          break;
       }
       return REF_SUCCEED;
    }
    
    Interval bhkRigidBodyModifier::GetValidity (TimeValue t) {
       Interval ret = FOREVER;
       pblock->GetValidity (t, ret);
       return ret;
    }
    
    void bhkRigidBodyModifier::ModifyObject (TimeValue t, ModContext &mc, ObjectState *os, INode *inode) 
    {
    
    Tazpn's avatar
    Tazpn committed
    	OutputDebugString("bhkRigidBodyModifier::ModifyObject\n");
    	int bvType = 0;
    	pblock->GetValue(PB_BOUND_TYPE, 0, bvType, FOREVER, 0);
    	if (bvType == 0)
    		return;
    
    	TriObject *tobj=NULL;
    	bool needsDelete(false);
    	if (os->obj->IsSubClassOf(triObjectClassID)) 
    		tobj = (TriObject*)os->obj;
    	else {
    		if (os->obj->CanConvertToType (triObjectClassID)) {
    			tobj = (TriObject *) os->obj->ConvertToType (t, triObjectClassID);
    			if (tobj != os->obj) needsDelete = true;
    		}
    	}
    	if (!tobj) return;	// If it's not an object we support, don't go any further.
    
    Tazpn's avatar
    Tazpn committed
    	Mesh& mesh = tobj->GetMesh();
    #if VERSION_3DSMAX >= ((5000<<16)+(15<<8)+0) // Version 5+
    	proxyMesh.CopyBasics(mesh);
    #else
    	proxyMesh = mesh;
    #endif
    
    	switch (bvType)
    	{ 
    	default:
    	case bv_type_none:
    		// Delete mesh.
    		break;
    
    	case bv_type_box: // box
    		BuildColBox(proxyMesh);
    		break;
    
    	case bv_type_sphere: // sphere
    		BuildColSphere(proxyMesh);
    		break;
    
    	case bv_type_shapes: // Shapes
    		BuildColStrips(proxyMesh);
    
    		BuildOptimize(proxyMesh);
    
    Tazpn's avatar
    Tazpn committed
    		break;
    
    
    	case bv_type_capsule:
    		BuildColCapsule(proxyMesh);
    		break;
    
    
    Tazpn's avatar
    Tazpn committed
    	//case bv_type_packed: // Packed
    	//	BuildColPackedStrips();
    	//	//BuildSphere();
    	//	break;
    
    
    Tazpn's avatar
    Tazpn committed
    		BuildColConvex(proxyMesh);
    
    		BuildOptimize(proxyMesh);
    
    Tazpn's avatar
    Tazpn committed
    		//BuildScubaMesh();
    		break;
    	}
    
    	proxyMesh.buildNormals();
    
    Tazpn's avatar
    Tazpn committed
    
    	if (needsDelete) {
    		os->obj = tobj;
    		os->obj->UnlockObject ();
    	}
    
       //Modifier::ModifyObject(t, mc, os, inode);
    }
    void bhkRigidBodyModifier::NotifyInputChanged(Interval changeInt, PartID partID, RefMessage message, ModContext *mc)
    {
    	OutputDebugString("bhkRigidBodyModifier::NotifyInputChanged\n");
       Modifier::NotifyInputChanged(changeInt, partID, message, mc);
    
    }
    
    
    //struct ParamMapInfo
    //{
    //	MapID mapid;
    //	DWORD idd;
    //	DWORD ids;
    //};
    //static ParamMapInfo pminfo[] = {
    //	{bv_box,		IDD_RB_MOD_PANEL1,	IDS_RB_MOD_PANEL1},
    //	{bv_sphere,	IDD_RB_MOD_PANEL2,	IDS_RB_MOD_PANEL2},
    //	{bv_capsule,IDD_RB_MOD_PANEL3,	IDS_RB_MOD_PANEL3},
    //	{bv_mesh,	IDD_RB_MOD_PANEL4,	IDS_RB_MOD_PANEL4},
    //};
    
    
    void bhkRigidBodyModifier::UpdateBVDialogs()
    {
    	//if (NULL != pmapParam)
    	//{
    	//	int bvType = pblock2->GetInt(PB_BOUND_TYPE);
    	//	if (bvType > 0) // none
    	//	{
    	//		int adjBvType = bvType - 1; //adjusted bvtype (ignoring none).
    	//		for (int i=0; i<_countof(pminfo), ++i){
    	//			if (pbvParams[i] != NULL && adjBvType != i)  {
    	//				DestroyCPParamMap2( pbvParams[i] );
    	//				pbvParams[i] = 0;
    	//			}
    	//		}
    	//		Interface *ifc = GetCOREInterface();
    	//		if (pbvParams[adjBvType] == NULL) {
    	//			pbvParams[adjBvType] = CreateCPParamMap2( pminfo[adjBvType], pblock2, ifc, hInstance, 
    	//				MAKEINTRESOURCE(pminfo[adjBvType]), GetString([adjBvType]), 0);
    	//		}
    	//	}
    	//}
    	//else
    	//{
    	//	// hide em all
    	//	for (int i=0; i<_countof(pminfo), ++i){
    	//		if (pbvParams[i] != NULL)  {
    	//			DestroyCPParamMap2( pbvParams[i] );
    	//			pbvParams[i] = 0;
    	//		}
    	//	}
    	//}
    }
    
    void bhkRigidBodyModifier::BeginEditParams(IObjParam  *ip, ULONG flags,Animatable *prev)
    {
       Modifier::BeginEditParams(ip, flags, prev);
    	mIP = ip;
    
       TimeValue t = ip->GetTime();
       NotifyDependents(Interval(t,t), PART_ALL, REFMSG_BEGIN_EDIT);
       NotifyDependents(Interval(t,t), PART_ALL, REFMSG_MOD_DISPLAY_ON);
       SetAFlag(A_MOD_BEING_EDITED);
       
       bhkRigidBodyModifierDesc.BeginEditParams(ip,this,flags,prev);
    
    Tazpn's avatar
    Tazpn committed
       havok_param_blk.SetUserDlgProc(havok_params, new bhkRigidBodyModifierDlgProc(this));
    
    Tazpn's avatar
    Tazpn committed
       havok_param_blk.SetUserDlgProc(clone_params, new CloneMeshDlgProc(this));
    
    Tazpn's avatar
    Tazpn committed
    	//pmapParam = pblock->GetMap(havok_params);
    	//UpdateBVDialogs();
    
    	//pmapParam->GetIRollup()->Hide(1);
    	//pmapParam->GetIRollup()->Hide(3);
    
    
    Tazpn's avatar
    Tazpn committed
       // BeginEditRBParams(ip, flags, prev);
    
    
       mNodes.ZeroCount();
    }
    	
    void bhkRigidBodyModifier::EndEditParams (IObjParam *ip,ULONG flags,Animatable *next)
    {
       Modifier::EndEditParams(ip,flags,next);
       //saveState();
       mNodes.ZeroCount();
    	mIP = NULL;
    
       // NOTE: This flag must be cleared before sending the REFMSG_END_EDIT
       ClearAFlag(A_MOD_BEING_EDITED);
       TimeValue t = ip->GetTime();
       NotifyDependents(Interval(t,t), PART_ALL, REFMSG_END_EDIT);
       NotifyDependents(Interval(t,t), PART_ALL, REFMSG_MOD_DISPLAY_OFF);
    
       havok_param_blk.SetUserDlgProc();
    
       if (flags&END_EDIT_REMOVEUI) {
    		pmapParam = NULL;
    		UpdateBVDialogs();
    	}
    
       // For PB2 we ask the ClassDesc2 to take care of the EndEditParams - NH
       bhkRigidBodyModifierDesc.EndEditParams(ip,this,flags,next);
    
    Tazpn's avatar
    Tazpn committed
       //EndEditRBParams(ip, flags, next);
    
    }
    
    class CollisionWireMtl: public Material 
    {
    public:
       CollisionWireMtl();
    };
    static CollisionWireMtl swMtl;
    CollisionWireMtl::CollisionWireMtl():Material() 
    {	
       Ks[0] = Kd[0] = 1.0f;
       Ks[1] = Kd[1] = 0.0f;
       Ks[2] = Kd[2] = 0.0f;
       shininess = (float)0.0;
       shadeLimit = GW_WIREFRAME|GW_BACKCULL;
       selfIllum = (float)1.0;
    }
    
    int bhkRigidBodyModifier::Display(TimeValue t, INode* inode, ViewExp *vpt, int flagst, ModContext *mc)
    {
    
    Tazpn's avatar
    Tazpn committed
    	//OutputDebugString("bhkRigidBodyModifier::Display\n");
    	if (!Modifier::IsEnabled())
    		return 0;
    
    	int bvType = 0;
    	pblock->GetValue(PB_BOUND_TYPE, 0, bvType, FOREVER, 0);
    	if (bvType == 0)
    		return 0;
    
    
    	Matrix3 m;
    	GraphicsWindow *gw = vpt->getGW();
    
    
    Tazpn's avatar
    Tazpn committed
    	int wrgb = inode->GetWireColor();
    	inode->SetWireColor( RGB(255,0,0) );
    
    Tazpn's avatar
    Tazpn committed
    	Material *mtl = &swMtl;
    	//gw->setTransform(mat);
    	if (inode->Selected()) 
    		gw->setColor( LINE_COLOR, GetSelColor());
    	else if(!inode->IsFrozen())
    		gw->setColor(LINE_COLOR,GetUIColor(COLOR_SPACE_WARPS));
    
    
    	m = inode->GetObjectTM(t);
    	gw->setTransform(m);
    	DWORD rlim = gw->getRndLimits();
    
    Tazpn's avatar
    Tazpn committed
    	DWORD newrlim = GW_WIREFRAME/*|GW_Z_BUFFER*/;
    
    #if VERSION_3DSMAX >= ((5000<<16)+(15<<8)+0) // Version 5+
    
    Tazpn's avatar
    Tazpn committed
    	newrlim |= GW_EDGES_ONLY;
    
    #endif
    
    Tazpn's avatar
    Tazpn committed
    	gw->setRndLimits(newrlim);
    
    
    	//UpdateMesh(t);
    
    Tazpn's avatar
    Tazpn committed
    	gw->setMaterial(swMtl);
    	gw->setColor(LINE_COLOR, 1.0f, 0.0f, 0.0f);
    	gw->setColor(FILL_COLOR, 1.0f, 0.0f, 0.0f);
    	proxyMesh.render( gw, mtl, NULL, COMP_ALL);	
    
    Tazpn's avatar
    Tazpn committed
    	inode->SetWireColor(wrgb);
    
    	gw->setRndLimits(rlim);
    
    	return 0;
    
    Tazpn's avatar
    Tazpn committed
    }
    
    void bhkRigidBodyModifier::BuildEmpty(Mesh& mesh)
    {
    }
    
    void bhkRigidBodyModifier::BuildColBox(Mesh& mesh)
    {
    	Box3 box; box.Init();
    	CalcAxisAlignedBox(mesh, box, NULL);
    	BuildBox(mesh, box.Max().y-box.Min().y, box.Max().x-box.Min().x, box.Max().z-box.Min().z);
    
    	MNMesh mn(mesh);
    	Matrix3 tm(true);
    	tm.Translate(box.Center());
    	mn.Transform(tm);
    	mn.OutToTri(mesh);
    }
    
    void bhkRigidBodyModifier::BuildColSphere(Mesh& mesh)
    {
    	Point3 center = Point3::Origin;
    	float radius = 0.0f;
    	CalcAxisAlignedSphere(mesh, center, radius);
    	BuildSphere(mesh, radius);
    
    	MNMesh mn(mesh);
    	Matrix3 tm(true);
    	tm.Translate(center);
    	mn.Transform(tm);
    	mn.OutToTri(mesh);
    }
    
    void bhkRigidBodyModifier::BuildColCapsule(Mesh& mesh)
    {
    
    	Point3 pt1 = Point3::Origin;
    	Point3 pt2 = Point3::Origin;
    	float r1 = 0.0;
    	float r2 = 0.0;
    
    Tazpn's avatar
    Tazpn committed
    
    
    	CalcCapsule(mesh, pt1, pt2, r1, r2);
    	BuildCapsule(mesh, pt1, pt2, r1, r2);
    
    Tazpn's avatar
    Tazpn committed
    }
    
    void bhkRigidBodyModifier::BuildColStrips(Mesh& mesh)
    {
    	MeshDelta tmd (mesh);
    	tmd.Apply(mesh);
    }
    
    void bhkRigidBodyModifier::BuildColPackedStrips(Mesh& mesh)
    {
    	BuildColStrips(mesh);
    }
    
    void bhkRigidBodyModifier::BuildColConvex(Mesh& mesh)
    {
    	extern void compute_convex_hull(Mesh& mesh, Mesh& outmesh);
    
    	compute_convex_hull(mesh, mesh);
    }
    
    
    void bhkRigidBodyModifier::BuildOptimize(Mesh& mesh)
    {
    	BOOL enable = FALSE;
    	pblock->GetValue(PB_OPT_ENABLE, 0, enable, FOREVER, 0);
    	if (enable)
    	{
    		float maxedge, facethresh, edgethresh, bias;
    		pblock->GetValue(PB_MAXEDGE, 0, maxedge, FOREVER, 0);
    		pblock->GetValue(PB_FACETHRESH, 0, facethresh, FOREVER, 0);
    		pblock->GetValue(PB_EDGETHRESH, 0, edgethresh, FOREVER, 0);
    		pblock->GetValue(PB_BIAS, 0, bias, FOREVER, 0);
    
    		DWORD flags = OPTIMIZE_AUTOEDGE;
    		mesh.Optimize(facethresh, edgethresh, bias, maxedge, flags, NULL);
    	}
    
    Tazpn's avatar
    Tazpn committed
    }
    
    void bhkRigidBodyModifier::CreateMesh()
    {
    	if (Interface *gi = this->mIP)
    	{
    		if (const Mesh* pMesh = this->GetMesh())
    		{
    			if (TriObject *triObject = CreateNewTriObject())
    			{
    				MNMesh mnmesh(*pMesh);
    				Mesh& mesh = triObject->GetMesh();
    				mnmesh.buildNormals();
    				mnmesh.OutToTri(mesh);
    
    				INode *node = gi->CreateObjectNode(triObject);
    
    				// Wireframe Red color
    				StdMat2 *collMat = NewDefaultStdMat();
    				collMat->SetDiffuse(Color(1.0f, 0.0f, 0.0f), 0);
    				collMat->SetWire(TRUE);
    				collMat->SetFaceted(TRUE);
    				gi->GetMaterialLibrary().Add(collMat);
    				node->SetMtl(collMat);
    
    				node->SetPrimaryVisibility(FALSE);
    				node->SetSecondaryVisibility(FALSE);
    				node->BoneAsLine(TRUE);
    				node->SetRenderable(FALSE);
    				node->SetWireColor( RGB(255,0,0) );
    
    				if (gi->GetSelNodeCount() == 1)
    				{
    					if (INode *snode = gi->GetSelNode(0))
    					{
    						Matrix3 tm = snode->GetObjTMAfterWSM(0, NULL);
    						node->SetNodeTM(0, tm);
    					}
    				}
    				gi->SelectNode(node);
    			}
    		}
    	}