Skip to content
Snippets Groups Projects
bhkRigidBodyModifer.cpp 22.8 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"
    
    using namespace std;
    
    #define PBLOCK_REF	0
    const Class_ID BHKRIGIDBODYMODIFIER_CLASS_ID = Class_ID(0x398fd801, 0x303e44e5);
    class PickObjectMode;
    
    extern void BuildBox(Mesh&mesh, float l, float w, float h);
    extern void BuildSphere(Mesh&mesh, float radius, int segs=32, int smooth=1, float startAng = 0.0f);
    extern void BuildScubaMesh(Mesh &mesh, int segs, int smooth, int llsegs, 
                        float radius1, float radius2, float cylh);
    
    void CalcAxisAlignedBox(Mesh& mesh, Box3& box)
    {
       int nv = mesh.getNumVerts();
       box.IncludePoints(mesh.getVertPtr(0), nv, NULL);
    }
    
    // Calculate bounding sphere using minimum-volume axis-align bounding box.  Its fast but not a very good fit.
    void CalcAxisAlignedSphere(Mesh& mesh, Point3& center, float& radius)
    {
       //--Calculate center & radius--//
    
       //Set lows and highs to first vertex
       int nv = mesh.getNumVerts();
       
       Point3 lows = mesh.getVert(0);
       Point3 highs = mesh.getVert(0);
    
       //Iterate through the vertices, adjusting the stored values
       //if a vertex with lower or higher values is found
       for ( unsigned int i = 0; i < nv; ++i ) {
          const Point3 & v = mesh.getVert(i);
    
          if ( v.x > highs.x ) highs.x = v.x;
          else if ( v.x < lows.x ) lows.x = v.x;
    
          if ( v.y > highs.y ) highs.y = v.y;
          else if ( v.y < lows.y ) lows.y = v.y;
    
          if ( v.z > highs.z ) highs.z = v.z;
          else if ( v.z < lows.z ) lows.z = v.z;
       }
    
       //Now we know the extent of the shape, so the center will be the average
       //of the lows and highs
       center = (highs + lows) / 2.0f;
    
       //The radius will be the largest distance from the center
       Point3 diff;
       float dist2(0.0f), maxdist2(0.0f);
       for ( unsigned int i = 0; i < nv; ++i ) {
          const Point3 & v = mesh.getVert(i);
    
          diff = center - v;
          dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
          if ( dist2 > maxdist2 ) maxdist2 = dist2;
       };
       radius = sqrt(maxdist2);
    }
    
    // Calculate bounding sphere using average position of the points.  Better fit but slower.
    void CalcCenteredSphere(Mesh& mesh, Point3& center, float& radius)
    {
    
       Point3 sum;
    
          sum += mesh.getVert(i);
       center = sum / float(nv);
       float radsq = 0.0f;
    
          Point3 diff = mesh.getVert(i) - center;
          float mag = diff.LengthSquared();
          radsq = max(radsq, mag);
       }
       radius = Sqrt(radsq);
    }
    
    
    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;
       };
    };
    
    enum { bv_type_none, bv_type_box, bv_type_sphere, bv_type_capsule, bv_type_mesh };  // pblock ID
    
    class bhkRigidBodyModifier : public Modifier, public bhkRigidBodyIfcHelper
    {
    
    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);
    
    
    	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();
    
       BaseInterface *GetInterface(Interface_ID id) {
          if (id == BHKRIGIDBODYINTERFACE_DESC)
             return this;
          return Modifier::GetInterface(id);
       }
    
    public:
       friend class PickObjectMode;
    
       StdMat2* collMat;
    	Mesh mesh;
    
       PickObjectMode *pickObMode;
    	IParamBlock2 *pblock;
       IParamMap2 *pmapParam;
    	IParamMap2 *pbvParams[4]; //box, sphere, capsule, proxy
    
    	Interface		*mIP;
       Tab<INode*> mNodes;
    
    	NpComboBox		mCbLayer;
    	NpComboBox		mCbMaterial;
    	NpComboBox		mCbMotionSystem;
    	NpComboBox		mCbQualityType;
       bhkValidatorClass validator;
       ICustButton		*iPickButton;
    
    	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
    enum { havok_params, bv_box, bv_sphere, bv_capsule, bv_mesh};  // pblock ID
    enum { PB_BOUND_TYPE, PB_MESHLIST, };
    enum { havok_params_panel, };
    
    class BVTypePBAccessor : public PBAccessor
    { 
    public:
    
    	void Set(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t)    // set from v
    	{
    		bhkRigidBodyModifier* p = (bhkRigidBodyModifier*)owner;
    		switch (id)
    		{
    		case PB_BOUND_TYPE:
    			{
    				switch (v.i)
    				{ 
                case bv_type_none:
                   // Delete mesh.
                   break;
    
                case bv_type_box: // Box
                   
                   //BuildBox(mesh,,,)
                   break;
    
                case bv_type_sphere: // Sphere
                   //BuildSphere();
                   break;
    
                case bv_type_capsule: // Capsule
                   //BuildScubaMesh();
                   break;
    
                case bv_type_mesh: 
                   break;
    				}
    			}
    		}
    	}
    };
    
    
    static BVTypePBAccessor bv_type_accessor;
    
    
    static ParamBlockDesc2 havok_param_blk ( 
       havok_params, _T("BoundingVolumes"),  0, NULL, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, PBLOCK_REF,
       //rollout
       2,
       havok_params,	IDD_RB_MOD_PANEL,  IDS_PARAMS, 0, 0, NULL, 
    	bv_mesh,			IDD_RB_MOD_PANEL4, IDS_RB_MOD_PANEL4, 0, 0, NULL, 
    
    	PB_BOUND_TYPE, 	_T("boundType"),	TYPE_INT, 0, IDS_BV_BOUNDING_TYPE,
    		p_default, 		0, 
    		p_range, 		0, 4, 
    		p_ui, 			havok_params,	TYPE_RADIO, 5, IDC_RDO_NO_COLL, IDC_RDO_AXIS_ALIGNED_BOX, IDC_RDO_SPHERE, IDC_RDO_CAPSULE, IDC_RDO_PROXY_MESH,
    		p_accessor,		&bv_type_accessor,
    		end,
    
    	PB_MESHLIST,   _T("meshList"),  TYPE_INODE_TAB,		0,	P_AUTO_UI|P_VARIABLE_SIZE,	IDS_MESHLIST,
    		p_ui,       bv_mesh, TYPE_NODELISTBOX, IDC_LIST1,IDC_ADD,0,IDC_REMOVE,
    		end,
    
    #if 0
       // params
       PB_RB_LAYER, _T("Layer"), TYPE_INT, 0,	IDS_DS_LAYER,
          p_default,	NP_DEFAULT_HVK_LAYER,
       end,
    
       PB_RB_MATERIAL, _T("Material"), TYPE_INT, 0,	IDS_DS_MATERIAL,
          p_default,	NP_DEFAULT_HVK_MATERIAL,
       end,
    
       PB_RB_MASS, _T("mass"), TYPE_FLOAT, 0,	IDS_DS_MASS,
          p_default,	NP_DEFAULT_HVK_MASS,
          p_range,		0.0, 1000.0,
          p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE,  IDC_ED_MASS, IDC_SP_MASS, SPIN_AUTOSCALE,
       end,
    
       PB_RB_FRICTION, _T("friction"), TYPE_FLOAT, 0,	IDS_DS_FRICTION,
          p_default,	NP_DEFAULT_HVK_FRICTION,
          p_range,		0.0, 10.0,
          p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE,  IDC_ED_FRICTION, IDC_SP_FRICTION, SPIN_AUTOSCALE,
       end,
    
       PB_RB_RESTITUTION, _T("restitution"), TYPE_FLOAT, 0,	IDS_DS_RESTITUTION,
          p_default,	NP_DEFAULT_HVK_RESTITUTION,
          p_range,		0.0, 10.0,
          p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE,  IDC_ED_RESTITUTION, IDC_SP_RESTITUTION, SPIN_AUTOSCALE,
       end,
    
       PB_RB_LINEAR_DAMPING, _T("linear_damping"), TYPE_FLOAT, 0,	IDS_DS_LINEAR_DAMPING,
          p_default,	NP_DEFAULT_HVK_LINEAR_DAMPING,
          p_range,		0.0, 10.0,
          p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE,  IDC_ED_LINEAR_DAMPING, IDC_SP_LINEAR_DAMPING, SPIN_AUTOSCALE,
       end,
    
       PB_RB_ANGULAR_DAMPING, _T("angular_damping"), TYPE_FLOAT, 0,	IDS_DS_ANGULAR_DAMPING,
          p_default,	NP_DEFAULT_HVK_ANGULAR_DAMPING,
          p_range,		0.0, 10.0,
          p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE,  IDC_ED_ANGULAR_DAMPING, IDC_SP_ANGULAR_DAMPING, SPIN_AUTOSCALE,
       end,
    
       PB_RB_MAX_LINEAR_VELOCITY, _T("max_linear_velocity"), TYPE_FLOAT, 0,	IDS_DS_MAX_LINEAR_VELOCITY,
          p_default,	NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY,
          p_range,		0.0, 10.0,
          p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE,  IDC_ED_MAX_LINEAR_VELOCITY, IDC_SP_MAX_LINEAR_VELOCITY, SPIN_AUTOSCALE,
       end,
    
       PB_RB_MAX_ANGULAR_VELOCITY, _T("max_angular_velocity"), TYPE_FLOAT, 0,	IDS_DS_MAX_ANGULAR_VELOCITY,
          p_default,	NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY,
          p_range,		0.0, 10.0,
          p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE,  IDC_ED_MAX_ANGULAR_VELOCITY, IDC_SP_MAX_ANGULAR_VELOCITY, SPIN_AUTOSCALE,
       end,
    
       PB_RB_PENETRATION_DEPTH, _T("penetration_depth"), TYPE_FLOAT, 0,	IDS_DS_PENETRATION_DEPTH,
          p_default,	NP_DEFAULT_HVK_PENETRATION_DEPTH,
          p_range,		0.0, 10.0,
          p_ui, TYPE_SPINNER, EDITTYPE_UNIVERSE,  IDC_ED_PENETRATION_DEPTH, IDC_SP_PENETRATION_DEPTH, SPIN_AUTOSCALE,
       end,
    
       PB_RB_MOTION_SYSTEM, _T("motion_system"), TYPE_INT, 0, IDS_DS_MOTION_SYSTEM,
          p_default,	NP_DEFAULT_HVK_MOTION_SYSTEM,
       end,
    
       PB_RB_QUALITY_TYPE, _T("quality_type"), TYPE_INT, 0,	IDS_DS_QUALITY_TYPE,
          p_default,	NP_DEFAULT_HVK_QUALITY_TYPE,
       end,
    #endif
    
    
       //PB_HK_NODE, 		_T("node"), 		TYPE_INODE, 	0,		IDS_DS_NODE,
       //   p_ui, 			TYPE_PICKNODEBUTTON,    IDC_PICK_NODE, 
       //   p_prompt,      IDS_PICKNODE_PROMPT,
       //   //p_validator, &validator,
       end,
       end
       );
    
    static bhkRigidBodyModifierClassDesc bhkRigidBodyModifierDesc;
    ClassDesc2* GetbhkRigidBodyModifierDesc() { return &bhkRigidBodyModifierDesc; }
    ParamBlockDesc2& get_havok_param_blk() {
       return havok_param_blk;
    }
    
    
    class PickObjectMode : 
       public PickModeCallback,
       public PickNodeCallback {
    public:		
       bhkRigidBodyModifier *mod;
    
       BOOL HitTest(IObjParam *ip,HWND hWnd,ViewExp *vpt,IPoint2 m,int flags);
       BOOL Pick(IObjParam *ip,ViewExp *vpt);
       void EnterMode(IObjParam *ip);
       void ExitMode(IObjParam *ip);
       BOOL RightClick(IObjParam *ip,ViewExp *vpt)	{return TRUE;}
       BOOL Filter(INode *node);		
       PickNodeCallback *GetFilter() {return this;}
    };
    
    //--- PickObjectMode ------------------------------------------------
    
    BOOL PickObjectMode::Filter(INode *node)
    {
       if (node) {
          node->BeginDependencyTest();
          mod->NotifyDependents(FOREVER,0,REFMSG_TEST_DEPENDENCY);
          if (node->EndDependencyTest()) {		
             return FALSE;
          } 
          ////added code for looptest
          //if (node->TestForLoop(FOREVER,(ReferenceMaker *) mod)!=REF_SUCCEED)
          //   return FALSE;
    
          for (int i = 0;i < mod->pblock->Count(PB_MESHLIST); i++) {
             INode *tnode = NULL;
             mod->pblock->GetValue(PB_MESHLIST,0,tnode,FOREVER,i);	
             if  (node == tnode)
                return FALSE;
          }
    
          ObjectState os = node->EvalWorldState(0);
          //added code such that lines are not selected
          if ( (os.obj->IsSubClassOf(triObjectClassID) || os.obj->CanConvertToType(triObjectClassID))
             && (os.obj->SuperClassID() != SHAPE_CLASS_ID) 
             ) 
          {			
             return TRUE;
          }
          if (os.obj->SuperClassID() == HELPER_CLASS_ID && os.obj->ClassID().PartB() == BHKRIGIDBODYCLASS_DESC.PartB() ) {
             return TRUE;
          }
       }
       return FALSE;
    }
    
    BOOL PickObjectMode::HitTest(
                                 IObjParam *ip,HWND hWnd,ViewExp *vpt,IPoint2 m,int flags)
    {
       INode *node = mod->mIP->PickNode(hWnd,m, this);	//added "this" argument such that the Filter above is used
       return node?TRUE:FALSE;
    }
    
    BOOL PickObjectMode::Pick(IObjParam *ip,ViewExp *vpt)
    {
       BOOL rv = FALSE;
       if (INode *node = vpt->GetClosestHit()) {
          theHold.Begin();
          ObjectState os = node->EvalWorldState(0);
          if (os.obj->CanConvertToType(triObjectClassID)) {
             mod->pblock->Append(PB_MESHLIST,1,&node,1);
             rv = TRUE;
          }
          theHold.Accept(GetString(IDS_ADD_MESH));
       }
       return rv;
    }
    
    void PickObjectMode::EnterMode(IObjParam *ip)
    {mod->iPickButton->SetCheck(TRUE);}
    
    void PickObjectMode::ExitMode(IObjParam *ip)
    {mod->iPickButton->SetCheck(FALSE);}
    
    static PickObjectMode thePickMode;
    
    class bhkRigidBodyModifierDlgProc : public ParamMap2UserDlgProc {
    public:
       bhkRigidBodyModifier *mod;
       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:
          //mod->iPickButton = GetICustButton(GetDlgItem(hWnd, IDC_ADD));
          //mod->iPickButton->SetType(CBT_CHECK);
          //mod->iPickButton->SetHighlightColor(GREEN_WASH);
          break;
    
       case WM_DESTROY:
          if (mod && mod->iPickButton != NULL) {
             ReleaseICustButton(mod->iPickButton);
             mod->iPickButton = NULL;
          }
          break;
    
       case WM_COMMAND:
          switch (LOWORD(wParam))
          {
          case IDC_ADD:
             {
                thePickMode.mod = mod;
                GetCOREInterface()->SetPickMode(&thePickMode);
                break;
             }
          }
          break;
    
       default:
          return FALSE;
       }
    
       return TRUE;
    }
    
    //--- bhkRigidBodyModifier -------------------------------------------------------
    
    bhkRigidBodyModifier::bhkRigidBodyModifier()
    {
    	mIP = NULL;	
    	pblock = NULL;
       pmapParam = NULL;
       pickObMode = NULL;
       validator.mod = this;
       iPickButton = NULL;
       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 0
       if (NULL != pickObMode) {
          delete pickObMode;
          pickObMode = NULL;
       }
    #endif
       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()
    {
       return 2;
    }
    
    RefTargetHandle bhkRigidBodyModifier::GetReference(int i)
    {
       if (i==0) return pblock;
       if (i==1) return GetRBBlock();
       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);
          if (changing_param == PB_MESHLIST)
          {
             if (partID == PART_TOPO) {
                NotifyDependents(FOREVER,GEOM_CHANNEL,REFMSG_CHANGE);
             }
          }
          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) 
    {
    OutputDebugString("bhkRigidBodyModifier::ModifyObject\n");
    
    	Box3 box; box.Init();
       if (TriObject *tri = (TriObject *)os->obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0)))
       {
          CalcAxisAlignedBox(tri->GetMesh(), box);
          BuildBox(mesh, box.Max().x-box.Min().x, box.Max().y-box.Min().y, box.Max().z-box.Min().z);
       }
       //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);
       //havok_param_blk.SetUserDlgProc(bv_mesh, new bhkRigidBodyModifierDlgProc(this));
    
    	pmapParam = pblock->GetMap(havok_params);
    	UpdateBVDialogs();
    	//pmapParam->GetIRollup()->Hide(1);
    	//pmapParam->GetIRollup()->Hide(3);
    
       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();
    	}
    
       if (iPickButton != NULL) {
          ReleaseICustButton(iPickButton);
          iPickButton = NULL;
       }
    
       // For PB2 we ask the ClassDesc2 to take care of the EndEditParams - NH
       bhkRigidBodyModifierDesc.EndEditParams(ip,this,flags,next);
       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)
    {
       //OutputDebugString("bhkRigidBodyModifier::Display\n");
       if (!Modifier::IsEnabled())
          return 0;
    
    	Matrix3 m;
    	GraphicsWindow *gw = vpt->getGW();
    
       int wrgb = inode->GetWireColor();
       inode->SetWireColor( RGB(255,0,0) );
    
       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();
    
    
       DWORD newrlim = GW_WIREFRAME/*|GW_Z_BUFFER*/;
    #if VERSION_3DSMAX >= ((5000<<16)+(15<<8)+0) // Version 5+
       newrlim |= GW_EDGES_ONLY;
    #endif
       gw->setRndLimits(newrlim);
    
    
    	//UpdateMesh(t);
       gw->setMaterial(swMtl);
       gw->setColor(LINE_COLOR, 1.0f, 0.0f, 0.0f);
       gw->setColor(FILL_COLOR, 1.0f, 0.0f, 0.0f);
    	mesh.render( gw, mtl, NULL, COMP_ALL);	
    
       inode->SetWireColor(wrgb);
    	gw->setRndLimits(rlim);
    
    	return 0;
    }