Skip to content
Snippets Groups Projects
bhkProxyObj.cpp 25 KiB
Newer Older
Tazpn's avatar
Tazpn committed
/**********************************************************************
*<
FILE: bhkProxyObj.cpp

DESCRIPTION:	Collision Proxy Object Implementation

CREATED BY: tazpn (Theo)

HISTORY: 
  V1.0 - Derived from 3ds max prim box example

*>	Copyright (c) 2006, All Rights Reserved.
**********************************************************************/
#pragma warning( disable:4800 )
#include <max.h>
#include "MAX_Mem.h"
#include <map>
#include "NifProps.h"
#include "iparamm.h"
#include "Simpobj.h"
#include "surf_api.h"
#include "notify.h"
#include "macroRec.h"
#include "bhkRigidBodyInterface.h"
#include "NifGui.h"
#include "NifStrings.h"
#include "bhkHelperFuncs.h"
#include "meshdelta.h"
#ifndef _countof
#define _countof(x) (sizeof(x)/sizeof((x)[0]))
#endif

extern void compute_convex_hull(Mesh& mesh, Mesh& outmesh);

Class_ID BHKPROXYOBJECT_CLASS_ID = Class_ID(0x3f087788, BHKRIGIDBODYCLASS_DESC.PartB());
class ProxyPickObjectMode;

class bhkProxyValidatorClass : public PBValidator
{
public:
	class bhkProxyObject *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;
		}
		return FALSE;
	};
};

class bhkProxyObject : public SimpleObject2
{
	typedef SimpleObject2 BaseClass;
public:			
   // Class vars
   IParamMap2 *pmapParam;
   IObjParam *ip;
   ProxyPickObjectMode *pickObMode;
   IParamMap2 *pbvParams[1]; //proxy
   Interface		*mIP;
   bhkProxyValidatorClass validator;
   ICustButton		*iPickButton;
   Mesh proxyMesh;
   Point3 proxyPos;
   bool forceRedraw;

   bhkProxyObject(BOOL loading);		
   ~bhkProxyObject();		

   // From Object
   int CanConvertToType(Class_ID obtype);
   Object* ConvertToType(TimeValue t, Class_ID obtype);
   void GetCollapseTypes(Tab<Class_ID> &clist,Tab<TSTR*> &nlist);

   CreateMouseCallBack* GetCreateMouseCallBack();
   void BeginEditParams( IObjParam  *ip, ULONG flags,Animatable *prev);
   void EndEditParams( IObjParam *ip, ULONG flags,Animatable *next);
   RefTargetHandle Clone(RemapDir& remap);
   TCHAR *GetObjectName() { return GetString(IDS_RB_PROXY); }

   int	NumParamBlocks() { return 1; }					// return number of ParamBlocks in this instance
   IParamBlock2* GetParamBlock(int i) { return pblock2; } // return i'th ParamBlock
   IParamBlock2* GetParamBlockByID(BlockID id) { return (pblock2->ID() == id) ? pblock2 : NULL; } // return id'd ParamBlock

   // Animatable methods		
   void DeleteThis() {delete this;}
   Class_ID ClassID() { return BHKPROXYOBJECT_CLASS_ID; } 
   SClass_ID SuperClassID() { return HELPER_CLASS_ID; }

   // From SimpleObject
   void BuildMesh(TimeValue t);
   BOOL OKtoDisplay(TimeValue t);
   void InvalidateUI();

   int Display(TimeValue t, INode* inode, ViewExp *vpt, int flags);

   void BuildEmpty();
   void BuildColBox();
   void BuildColStrips();
   void BuildColPackedStrips();
   void BuildColConvex();
   void BuildOptimize(Mesh&mesh);
Tazpn's avatar
Tazpn committed

   void UpdateUI();
Tazpn's avatar
Tazpn committed
   void CreateMesh();
Tazpn's avatar
Tazpn committed

   Modifier *CreateWSMMod(INode *)
   {
	   return NULL;
   }
};

//--- ClassDescriptor and class vars ---------------------------------

// The class descriptor for box
class bhkProxyObjClassDesc : public ClassDesc2 
{
public:
   bhkProxyObjClassDesc();
   int 			   IsPublic() { return 1; }
   void *			Create(BOOL loading = FALSE) {
      return new bhkProxyObject(loading);
   }
   const TCHAR *	ClassName() { return GetString(IDS_RB_PROXY_CLASS); }
   SClass_ID		SuperClassID() { return HELPER_CLASS_ID; }
   Class_ID		   ClassID() { return BHKPROXYOBJECT_CLASS_ID; }
   const TCHAR* 	Category() { return "NifTools"; }

   const TCHAR*	InternalName() { return _T("bhkProxyShape"); }	// returns fixed parsable name (scripter-visible name)
   HINSTANCE		HInstance() { return hInstance; }			// returns owning module handle
};

extern ClassDesc2* GetbhkProxyObjDesc();

// in prim.cpp  - The dll instance handle
extern HINSTANCE hInstance;

//--- Parameter map/block descriptors -------------------------------

// Parameter and ParamBlock IDs
Tazpn's avatar
Tazpn committed
enum { list_params, opt_params, clone_params, subshape_params };  // pblock2 ID
Tazpn's avatar
Tazpn committed
enum 
{ 
   PB_MATERIAL, PB_MESHLIST, PB_BOUND_TYPE, PB_CENTER,
   PB_OPT_ENABLE, PB_MAXEDGE, PB_FACETHRESH, PB_EDGETHRESH, PB_BIAS, 
Tazpn's avatar
Tazpn committed
   PB_LAYER, PB_FILTER, 
Tazpn's avatar
Tazpn committed
};

enum { bv_type_none, bv_type_box, bv_type_shapes, bv_type_packed, bv_type_convex, bv_type_capsule };  // pblock ID
Tazpn's avatar
Tazpn committed

static ParamBlockDesc2 param_blk ( 
    list_params, _T("parameters"),  0, NULL, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, 0,
    //rollout
Tazpn's avatar
Tazpn committed
    4,
Tazpn's avatar
Tazpn committed
    list_params, IDD_PROXYPARAM1, 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
	subshape_params,	IDD_RB_MOD_PANEL5,   IDS_LIST_SUBSHAPEPROPS, 0, 0, NULL,
Tazpn's avatar
Tazpn committed

    // params
    PB_MATERIAL, _T("material"), TYPE_INT, P_ANIMATABLE,	IDS_DS_MATERIAL,
Tazpn's avatar
Tazpn committed
      end,

    PB_BOUND_TYPE, 	_T("boundType"),	TYPE_INT, 0, IDS_BV_BOUNDING_TYPE,
	  p_default, 		0, 
	  p_range, 			0, 5, 
	  p_ui, 			list_params,	TYPE_RADIO, 6, IDC_RDO_NO_COLL, IDC_RDO_AXIS_ALIGNED_BOX, IDC_RDO_STRIPS_SHAPE, IDC_RDO_PACKED_STRIPS, IDC_RDO_CONVEX, IDC_RDO_CAPSULE,
Tazpn's avatar
Tazpn committed
	  end,

	PB_MESHLIST,   _T("meshProxy"),  TYPE_INODE_TAB,		0,	P_AUTO_UI|P_VARIABLE_SIZE,	IDS_MESHLIST,
	  p_ui,       list_params, TYPE_NODELISTBOX, IDC_LIST1,IDC_ADD,0,IDC_REMOVE,
	  end,

    PB_CENTER,   _T("center"),  TYPE_POINT3,  P_TRANSIENT,	IDS_CENTER,
	  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_MAXEDGE,		_T("maxEdge"),		TYPE_FLOAT, 0, IDS_OPT_MAXEDGE,
	  p_default, 	0.0f, 
	  p_range, 		0.0f, 1000.0f, 
	  p_ui,			opt_params, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_OPT_MAXEDGE, IDC_OPT_MAXEDGESPIN, SPIN_AUTOSCALE,
	  p_uix,		opt_params,
	  end,
Tazpn's avatar
Tazpn committed

	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,

Tazpn's avatar
Tazpn committed
    end
    );

// bug in pb desc? forces us to use this rather than in inline version
static bhkProxyObjClassDesc listDesc;
extern ClassDesc2* GetbhkProxyObjDesc() { return &listDesc; }
bhkProxyObjClassDesc::bhkProxyObjClassDesc() {
   param_blk.SetClassDesc(this);
}


class ProxyPickObjectMode : 
	public PickModeCallback,
	public PickNodeCallback {
public:		
	bhkProxyObject *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;}
};

//--- ProxyPickObjectMode ------------------------------------------------

BOOL ProxyPickObjectMode::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->pblock2->Count(PB_MESHLIST); i++) {
			INode *tnode = NULL;
			mod->pblock2->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 ProxyPickObjectMode::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 ProxyPickObjectMode::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->pblock2->Append(PB_MESHLIST,1,&node,1);
			rv = TRUE;
		}
		theHold.Accept(GetString(IDS_ADD_MESH));
	}
	return rv;
}

void ProxyPickObjectMode::EnterMode(IObjParam *ip)
{mod->iPickButton->SetCheck(TRUE);}

void ProxyPickObjectMode::ExitMode(IObjParam *ip)
{mod->iPickButton->SetCheck(FALSE);}

static ProxyPickObjectMode thePickMode;



class ProxyParamDlgProc : public ParamMap2UserDlgProc {
public:
   bhkProxyObject *so;
   HWND thishWnd;
   NpComboBox		mCbMaterial;

   ProxyParamDlgProc(bhkProxyObject *s) {so=s;thishWnd=NULL;}
   INT_PTR DlgProc(TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
   void Update(TimeValue t);
   void DeleteThis() {delete this;}

   //--- ParamDlgProc --------------------------------
   void TurnSpinner(HWND hWnd,int SpinNum,BOOL ison)
   {	
      ISpinnerControl *spin2 = GetISpinner(GetDlgItem(hWnd,SpinNum));
      if (ison) spin2->Enable();else spin2->Disable();
      ReleaseISpinner(spin2);
   };

};

void ProxyParamDlgProc::Update(TimeValue t)
{
   if (!thishWnd) 
      return;
   return;
}

INT_PTR ProxyParamDlgProc::DlgProc(TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
   thishWnd=hWnd;
   switch (msg) 
   {
   case WM_INITDIALOG: 
      {
		  mCbMaterial.init(GetDlgItem(hWnd, IDC_CB_MATERIAL));
		  mCbMaterial.add("<Default>");
		  for (const char **str = NpHvkMaterialNames; *str; ++str)
			  mCbMaterial.add(*str);
		  Interval valid;
		  int sel = NP_INVALID_HVK_MATERIAL;
		  so->pblock2->GetValue( PB_MATERIAL, 0, sel, valid);
		  mCbMaterial.select( sel + 1 );
		 // Disable all types not currently implemented
		  EnableWindow(GetDlgItem(hWnd, IDC_RDO_CAPSULE), CanCalcCapsule() ? TRUE : FALSE);
Tazpn's avatar
Tazpn committed
		 //EnableWindow(GetDlgItem(hWnd, IDC_RDO_PACKED_STRIPS), FALSE);
Tazpn's avatar
Tazpn committed

         Update(t);
         break;
      }
   case WM_DESTROY:
	   if (so && so->iPickButton != NULL) {
		   ReleaseICustButton(so->iPickButton);
		   so->iPickButton = NULL;
	   }
	   break;

   case WM_COMMAND:
      switch (LOWORD(wParam)) 
      {
      case IDC_CB_MATERIAL:
         if (HIWORD(wParam)==CBN_SELCHANGE) {
            so->pblock2->SetValue( PB_MATERIAL, 0, mCbMaterial.selection() - 1 );
Tazpn's avatar
Tazpn committed
         }
         break;
Tazpn's avatar
Tazpn committed

	  case IDC_BTN_CLONE:
		  so->CreateMesh();
		  break;
Tazpn's avatar
Tazpn committed
      }
      break;	
   }
   return FALSE;
}
Tazpn's avatar
Tazpn committed

namespace
{
	class CloneMeshDlgProc : public ParamMap2UserDlgProc {
	public:
		bhkProxyObject *mod;
		CloneMeshDlgProc(bhkProxyObject* m) {mod = m;}		
		void DeleteThis() {delete this;}		

		INT_PTR 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;
		}
	};

Tazpn's avatar
Tazpn committed

	// Controller for subshape properies: layer and filter
	class SubShapeDlgProc : public ParamMap2UserDlgProc {
	public:
		bhkProxyObject *mod;
		NpComboBox		mCbLayer;
		SubShapeDlgProc(bhkProxyObject* 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->pblock2->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->pblock2->SetValue( PB_LAYER, 0, mCbLayer.selection() );
				}
				break;

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

Tazpn's avatar
Tazpn committed
//--- Proxy methods -------------------------------


bhkProxyObject::bhkProxyObject(BOOL loading)
{
	pmapParam = NULL;
	ip = NULL;
	pickObMode = NULL;
	pbvParams[0] = NULL;
	mIP = NULL;	
	iPickButton = NULL;
	validator.mod = this;
	forceRedraw = false;

   SetAFlag(A_PLUGIN1);
   listDesc.MakeAutoParamBlocks(this);
   assert(pblock2);
}

bhkProxyObject::~bhkProxyObject() 
{
   param_blk.SetUserDlgProc();
   if (pmapParam) {
      pmapParam  = NULL;
   }
}

void bhkProxyObject::BeginEditParams(IObjParam *ip,ULONG flags,Animatable *prev)
{
   BaseClass::BeginEditParams(ip,flags,prev);
   mIP = ip;

   listDesc.BeginEditParams(ip,this,flags,prev);
   param_blk.SetUserDlgProc(new ProxyParamDlgProc(this));
Tazpn's avatar
Tazpn committed
   param_blk.SetUserDlgProc(clone_params, new CloneMeshDlgProc(this));
Tazpn's avatar
Tazpn committed
   param_blk.SetUserDlgProc(subshape_params, new SubShapeDlgProc(this));
Tazpn's avatar
Tazpn committed
   pmapParam = pblock2->GetMap(list_params);

   this->ip = ip;
}

void bhkProxyObject::EndEditParams( IObjParam *ip, ULONG flags,Animatable *next )
{		
   param_blk.SetUserDlgProc();

   BaseClass::EndEditParams(ip,flags,next);
   this->ip = NULL;
   pmapParam = NULL;

   if (iPickButton != NULL) {
	   ReleaseICustButton(iPickButton);
	   iPickButton = NULL;
   }

   // tear down the appropriate auto-rollouts
   listDesc.EndEditParams(ip, this, flags, next);
   mIP = NULL;
}

void bhkProxyObject::UpdateUI()
{
   if (ip == NULL)
      return;
   ProxyParamDlgProc* dlg = static_cast<ProxyParamDlgProc*>(pmapParam->GetUserDlgProc());
   dlg->Update(ip->GetTime());
}

enum 
{
   POSX = 0,	// right
   POSY = 1,	// back
   POSZ = 2,	// top
   NEGX = 3,	// left
   NEGY = 4,	// front
   NEGZ = 5,	// bottom
};

void bhkProxyObject::BuildMesh(TimeValue t)
{
	ivalid = FOREVER;	
	
	int bvType = 0;
	pblock2->GetValue(PB_BOUND_TYPE, 0, bvType, FOREVER, 0);

	BuildEmpty();
	
	switch (bvType)
	{ 
	default:
	case bv_type_none:
		// Delete mesh.
		break;

	case bv_type_box: // box
		BuildColBox();
		break;

	case bv_type_shapes: // Shapes
		BuildColStrips();
		//BuildBox(mesh,,,)
		break;

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

Tazpn's avatar
Tazpn committed
		BuildColConvex();
		//BuildScubaMesh();
		break;
Tazpn's avatar
Tazpn committed
	}
}

Object* bhkProxyObject::ConvertToType(TimeValue t, Class_ID obtype)
{
	if (obtype == triObjectClassID)
	{
		int bvType = 0;
		pblock2->GetValue(PB_BOUND_TYPE, 0, bvType, FOREVER, 0);
		if (bvType != 0) 
		{
			TriObject *ob = CreateNewTriObject();
#if VERSION_3DSMAX >= ((5000<<16)+(15<<8)+0) // Version 5+
			ob->GetMesh().CopyBasics(proxyMesh);
#else
			ob->GetMesh() = proxyMesh;
#endif
			ob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t));
			ob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t));
			return ob;
		}
	}
	return 0;
}

int bhkProxyObject::CanConvertToType(Class_ID obtype)
{
	if (obtype == triObjectClassID) {
		int bvType = 0;
		pblock2->GetValue(PB_BOUND_TYPE, 0, bvType, FOREVER, 0);
		return (bvType != 0) ? TRUE : FALSE;
	}
	return FALSE;
}


void bhkProxyObject::GetCollapseTypes(Tab<Class_ID> &clist,Tab<TSTR*> &nlist)
{
   Object::GetCollapseTypes(clist, nlist);
}

class ProxyObjCreateCallBack: public CreateMouseCallBack {
   bhkProxyObject *ob;
   Point3 p0,p1;
   IPoint2 sp0, sp1;
   BOOL square;
public:
   int proc( ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat );
   void SetObj(bhkProxyObject *obj) { ob = obj; }
};

int ProxyObjCreateCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ) {
   Point3 d;
   if (msg == MOUSE_FREEMOVE)
   {
      vpt->SnapPreview(m,m,NULL, SNAP_IN_3D);
   }

   else if (msg==MOUSE_POINT||msg==MOUSE_MOVE) {
      switch(point) {
         case 0:
            // Find the node and plug in the wire color
            {
               ULONG handle;
               ob->NotifyDependents(FOREVER, (PartID)&handle, REFMSG_GET_NODE_HANDLE);
               INode *node = GetCOREInterface()->GetINodeByHandle(handle);
               if (node) node->SetWireColor(RGB(255, 0, 0));
            }

            sp0 = m;
            //ob->suspendSnap = TRUE;								
            p0 = vpt->SnapPoint(m,m,NULL,SNAP_IN_3D);
            p1 = p0 + Point3(.01,.01,.01);
            mat.SetTrans(float(.5)*(p0+p1));				

			ob->pmapParam->Invalidate();				

            if (msg==MOUSE_POINT) 
            {
               //ob->suspendSnap = FALSE;					
               return CREATE_STOP;
            }
            break;
      }
   }
   else
      if (msg == MOUSE_ABORT) {		
         return CREATE_ABORT;
      }

      return TRUE;
}

static ProxyObjCreateCallBack listCreateCB;

CreateMouseCallBack* bhkProxyObject::GetCreateMouseCallBack() 
{
   listCreateCB.SetObj(this);
   return(&listCreateCB);
}


BOOL bhkProxyObject::OKtoDisplay(TimeValue t) 
{
   return TRUE;
}

void bhkProxyObject::InvalidateUI() 
{
   param_blk.InvalidateUI(pblock2->LastNotifyParamID());
   if (pmapParam) pmapParam->Invalidate();
}

RefTargetHandle bhkProxyObject::Clone(RemapDir& remap) 
{
   bhkProxyObject* newob = new bhkProxyObject(FALSE);	
   newob->ReplaceReference(0,remap.CloneRef(pblock2));
   newob->ivalid.SetEmpty();	
   BaseClone(this, newob, remap);
   return(newob);
}

int bhkProxyObject::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) 
{
	if (forceRedraw)
	{
		Interface *gi = GetCOREInterface();
		gi->ForceCompleteRedraw();
	}

	Matrix3 m;
	Color color = Color(inode->GetWireColor());
	GraphicsWindow *gw = vpt->getGW();
	Material *mtl = gw->getMaterial();
	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);

	if (inode->Selected()) 
		gw->setColor( LINE_COLOR, GetSelColor());
	else if(!inode->IsFrozen() && !inode->Dependent())
		gw->setColor( LINE_COLOR, color);

	Matrix3 m3(true);

	float size = 20.0f;
	Point3 pts[5];
	// X
	pts[0] = Point3(-size, 0.0f, 0.0f); pts[1] = Point3(size, 0.0f, 0.0f);
	vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);

	// Y
	pts[0] = Point3(0.0f, -size, 0.0f); pts[1] = Point3(0.0f, size, 0.0f);
	vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);

	// Z
	pts[0] = Point3(0.0f, 0.0f, -size); pts[1] = Point3(0.0f, 0.0f, size);
	vpt->getGW()->polyline(2, pts, NULL, NULL, FALSE, NULL);

	//UpdateMesh(t);

	int bvType = 0;
	pblock2->GetValue(PB_BOUND_TYPE, 0, bvType, FOREVER, 0);
	if (bvType != 0)
	{
		Matrix3 tm = gw->getTransform();
		Matrix3 proxyTM(true);
		proxyTM.SetTranslate(proxyPos);
		gw->setTransform(proxyTM);
		proxyMesh.render( gw, mtl, NULL, COMP_ALL);	
		gw->setTransform(tm);
	}
	gw->setRndLimits(rlim);
	return 0;
}

void bhkProxyObject::BuildEmpty()
{
	BuildBox(mesh, 10.0f, 10.0f, 10.0f);
	proxyMesh.FreeAll();
	proxyPos = Point3::Origin;
	forceRedraw = true;
}

void bhkProxyObject::BuildColBox()
{
	Box3 box; box.Init();
	for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) {
		INode *tnode = NULL;
		pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i);	
		if (tnode)
		{
			ObjectState os = tnode->EvalWorldState(0);
			Matrix3 wm = tnode->GetNodeTM(0);
			TriObject *tri = (TriObject *)os.obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));
			if (tri)
			{
				Box3 box2; box2.Init();
				Mesh& mesh = tri->GetMesh();
				CalcAxisAlignedBox(mesh, box2, &wm);
				box += box2;
			}
		}
	}
	BuildBox(proxyMesh, box.Max().y-box.Min().y, box.Max().x-box.Min().x, box.Max().z-box.Min().z);

	MNMesh mn(proxyMesh);
	Matrix3 tm(true);
	tm.SetTranslate(box.Center());
	mn.Transform(tm);
	mn.OutToTri(proxyMesh);

	//proxyPos = box.Center();
	proxyPos = Point3::Origin;
	forceRedraw = true;
}

void bhkProxyObject::BuildColStrips()
{
	proxyMesh.FreeAll();
	MeshDelta md(proxyMesh);
	for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) {
		INode *tnode = NULL;
		pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i);	
		if (tnode)
		{
			ObjectState os = tnode->EvalWorldState(0);
			Matrix3 wm = tnode->GetNodeTM(0);
			TriObject *tri = (TriObject *)os.obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));
			if (tri)
			{
				Mesh& mesh = tri->GetMesh();
				MeshDelta tmd (mesh);
				md.AttachMesh(proxyMesh, mesh, wm, 0);
				md.Apply(proxyMesh);
			}
		}
	}
	BuildOptimize(proxyMesh);
Tazpn's avatar
Tazpn committed
	proxyPos = Point3::Origin;
	forceRedraw = true;
}

void bhkProxyObject::BuildColPackedStrips()
{
	BuildColStrips();
}

void bhkProxyObject::BuildColConvex()
{
	proxyMesh.FreeAll();
	MeshDelta md(proxyMesh);
	for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) {
		INode *tnode = NULL;
		pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i);	
		if (tnode)
		{
			ObjectState os = tnode->EvalWorldState(0);
			Matrix3 wm = tnode->GetNodeTM(0);
			TriObject *tri = (TriObject *)os.obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));
			if (tri)
			{
				Mesh& mesh = tri->GetMesh();
				MeshDelta tmd (mesh);
				md.AttachMesh(proxyMesh, mesh, wm, 0);
				md.Apply(proxyMesh);
			}
		}
	}
	compute_convex_hull(proxyMesh, proxyMesh);

	BuildOptimize(proxyMesh);

Tazpn's avatar
Tazpn committed
	proxyPos = Point3::Origin;
	forceRedraw = true;
}
void bhkProxyObject::BuildColCapsule()
{
	proxyMesh.FreeAll();
	MeshDelta md(proxyMesh);
	for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) {
		INode *tnode = NULL;
		pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i);	
		if (tnode)
		{
			ObjectState os = tnode->EvalWorldState(0);
			Matrix3 wm = tnode->GetNodeTM(0);
			TriObject *tri = (TriObject *)os.obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));
			if (tri)
			{
				Mesh& mesh = tri->GetMesh();
				MeshDelta tmd (mesh);
				md.AttachMesh(proxyMesh, mesh, wm, 0);
				md.Apply(proxyMesh);
			}
		}
	}
	Point3 pt1 = Point3::Origin;
	Point3 pt2 = Point3::Origin;
	float r1 = 0.0;
	float r2 = 0.0;

	CalcCapsule(proxyMesh, pt1, pt2, r1, r2);
	BuildCapsule(proxyMesh, pt1, pt2, r1, r2);

	proxyPos = Point3::Origin;
	forceRedraw = true;
}


void bhkProxyObject::BuildOptimize(Mesh& mesh)
{
	BOOL enable = FALSE;
	pblock2->GetValue(PB_OPT_ENABLE, 0, enable, FOREVER, 0);
	if (enable)
	{
		float maxedge, facethresh, edgethresh, bias;
		pblock2->GetValue(PB_MAXEDGE, 0, maxedge, FOREVER, 0);
		pblock2->GetValue(PB_FACETHRESH, 0, facethresh, FOREVER, 0);
		pblock2->GetValue(PB_EDGETHRESH, 0, edgethresh, FOREVER, 0);
		pblock2->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 bhkProxyObject::CreateMesh()
{
	if (Interface *gi = this->mIP)
	{
		if (const Mesh* pMesh = &this->proxyMesh)
		{
			if (TriObject *triObject = CreateNewTriObject())
			{
				MNMesh mnmesh(*pMesh);
				Mesh& mesh = triObject->GetMesh();
				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) );

				gi->SelectNode(node);
			}
		}
	}