Skip to content
Snippets Groups Projects
bhkRigidBodyModifer.cpp 21.7 KiB
Newer Older
#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
enum { havok_params, opt_params, clone_params, subshape_params };  // pblock ID
enum { PB_BOUND_TYPE, PB_MATERIAL, PB_OPT_ENABLE, PB_MAXEDGE, PB_FACETHRESH, PB_EDGETHRESH, PB_BIAS, PB_LAYER, PB_FILTER, };
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, bv_type_packed, };  // 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
    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,
	subshape_params,	IDD_RB_MOD_PANEL5,   IDS_LIST_SUBSHAPEPROPS, 0, 0, NULL,
Tazpn's avatar
Tazpn committed
    PB_MATERIAL, _T("material"), TYPE_INT, P_ANIMATABLE,	IDS_DS_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, 
Tazpn's avatar
Tazpn committed
	  p_range, 		0, 6, 
	  p_ui, 			havok_params,	TYPE_RADIO, 7, IDC_RDO_NO_COLL, IDC_RDO_AXIS_ALIGNED_BOX, IDC_RDO_SPHERE, IDC_RDO_CAPSULE, IDC_RDO_PROXY_MESH, IDC_RDO_CONVEX, IDC_RDO_PACKED_STRIPS,
Tazpn's avatar
Tazpn committed
	  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,

	PB_LAYER, _T("layer"), TYPE_INT, P_ANIMATABLE,	IDS_DS_LAYER,
	  p_default,	NP_DEFAULT_HVK_LAYER,
	  end,

	PB_FILTER, _T("filter"), TYPE_INT, P_ANIMATABLE,	IDS_DS_FILTER,
	  p_default,	NP_DEFAULT_HVK_FILTER,
	  p_range, 		0, 255, 
	  p_ui,			subshape_params, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_ED_FILTER, IDC_SP_FILTER, 0.01f,
	  p_uix,		subshape_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));
Tazpn's avatar
Tazpn committed
		   for (const char **str = NpHvkMaterialNames; *str; ++str)
			   mCbMaterial.add(*str);
		   Interval valid;
Tazpn's avatar
Tazpn committed
		   mod->pblock->GetValue( PB_MATERIAL, 0, sel, valid);
		   EnableWindow(GetDlgItem(hWnd, IDC_RDO_CAPSULE), CanCalcCapsule() ? TRUE : 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() - 1 );
Tazpn's avatar
Tazpn committed
		   }
		   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;
	}


	// Controller for subshape properies: layer and filter
	class SubShapeDlgProc : public ParamMap2UserDlgProc {
	public:
		bhkRigidBodyModifier *mod;
		NpComboBox		mCbLayer;
		SubShapeDlgProc(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 SubShapeDlgProc::DlgProc (TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
		switch (msg) 
		{
		case WM_INITDIALOG:
			{
				mCbLayer.init(GetDlgItem(hWnd, IDC_CB_LAYER));
				for (const char **str = NpHvkLayerNames; *str; ++str)
					mCbLayer.add(*str);

				int sel = NP_DEFAULT_HVK_LAYER;
				Interval valid;
				mod->pblock->GetValue( PB_LAYER, 0, sel, valid);
				mCbLayer.select( sel );



				Update(t);
				break;
			}

		case WM_DESTROY:
			break;

		case WM_COMMAND:
			switch (LOWORD(wParam))
			{
			case IDC_CB_LAYER:
				if (HIWORD(wParam)==CBN_SELCHANGE) {
					mod->pblock->SetValue( PB_MATERIAL, 0, mCbLayer.selection() );
				}
				break;

			default:
				return FALSE;
			}
		}		
		return FALSE;
	}
	
Tazpn's avatar
Tazpn committed
}

//--- 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;

	case bv_type_convex:
Tazpn's avatar
Tazpn committed
		BuildColConvex(proxyMesh);
		BuildOptimize(proxyMesh);
Tazpn's avatar
Tazpn committed
		//BuildScubaMesh();
		break;
Tazpn's avatar
Tazpn committed

	case bv_type_packed: // Packed
		BuildColPackedStrips(proxyMesh);
		//BuildSphere();
		break;

Tazpn's avatar
Tazpn committed
	}
	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));
   havok_param_blk.SetUserDlgProc(subshape_params, new SubShapeDlgProc(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);
			}
		}
	}