//===========================================================================// // File: CvTool.cpp // Project: MechWarrior 4 // Contents: Plugin to add Collision Volumes to mech //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 06/10/99 jkyle Initial coding, //---------------------------------------------------------------------------// // Copyright (C) 1999, Fasa Interactive, Inc. // All Rights reserved worldwide // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //===========================================================================// #include "stdafx.h" #ifdef STRICT // Already defined by stdafx, #undef STRICT // so we avoid warning linking msg #endif #ifdef _MBCS // The same as above #undef _MBCS #endif #include "CvTool.hpp" #include "cvobject.h" #include "mw4.hpp" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif extern int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData); ////////////////////////////////////////////////////////////////////// // Global Variables CvToolPanel g_cvToolPanel; ////////////////////////////////////////////////////////////////////// // ProtoTypes //////////////////////////////////////////////////////////////////////////////// // CvToolPanel Dialog Procedure to handle User and System Interactions static BOOL CALLBACK CvToolPanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); switch (msg) { case WM_INITDIALOG: //Panel's extra initialization g_cvToolPanel.Init(hWnd); break; case WM_DESTROY: //Panel's extra destruction g_cvToolPanel.Destroy(hWnd); break; case WM_COMMAND : { //Handle Panel's controls HWND hwndCtrl = (HWND)lParam; switch (LOWORD(wParam)) { case IDC_EXECUTE: { //g_cvToolPanel.CvToolExecute(); theHold.SuperBegin(); g_cvToolPanel.BuildCollisionVolume(g_cvToolPanel.m_ip->GetRootNode()); theHold.SuperAccept("CollisionTool"); g_cvToolPanel.m_ip->RedrawViews(g_cvToolPanel.m_ip->GetTime(),REDRAW_BEGIN); g_cvToolPanel.m_ip->RedrawViews(g_cvToolPanel.m_ip->GetTime(),REDRAW_NORMAL); g_cvToolPanel.m_ip->RedrawViews(g_cvToolPanel.m_ip->GetTime(),REDRAW_END); } } break; } //////////////////////////////////////////////////////////////////////// //The following lines are not necessary for MAX2 Plugins case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MOUSEMOVE: g_cvToolPanel.m_ip->RollupMouseMessage(hWnd, msg, wParam, lParam); break; //////////////////////////////////////////////////////////////////////// default: return FALSE; } return TRUE; } //////////////////////////////////////////////////////////////////////////////// // Display the Plugin's Panel void CvToolPanel::BeginEditParams(Interface* ip, IUtil* iu) { m_ip = ip; //Get the Plugin's Interface m_iu = iu; //Get the Utility Plugin's Interface //Display the plugin's Rollup Dialog AFX_MANAGE_STATE(AfxGetStaticModuleState()); HINSTANCE loc_hInstance = AfxGetResourceHandle (); m_hPanel = ip->AddRollupPage(loc_hInstance, MAKEINTRESOURCE(IDD_CVTOOL_PANEL), CvToolPanelProc, GetString(IDS_CVOBJECT_NAME),0); } //////////////////////////////////////////////////////////////////////////////// // Free the Plugins' Panel void CvToolPanel::EndEditParams(Interface *ip, IUtil *iu) { m_iu = NULL; m_ip = NULL; //Remove the Rollup Dialog ip->DeleteRollupPage(m_hPanel); m_hPanel = NULL; } //////////////////////////////////////////////////////////////////////////////// // Panel Initialization callback void CvToolPanel::Init(HWND hWnd) { } //////////////////////////////////////////////////////////////////////////////// // Panel Destruction callback void CvToolPanel::Destroy(HWND hWnd) { } #if 0 void CvToolPanel::CvToolExecute() { INode *pRoot = ip->GetINodeByName("joint_WORLD"); if (pRoot) { // We are creating a mech Collision Volume //AddCvNode(pRoot,true); AddCv(pRoot); } else { // We are creating a building Collision Volume pRoot = ip->GetRootNode(); AddCv(pRoot,false); } // Redraw the views ip->RedrawViews(ip->GetTime()); } void CvToolPanel::AddCv(INode *pNode,BOOL bCheckName) { BOOL bValid = false; BOOL bIsJoint = false; if (bCheckName) { CString strName = pNode->GetName(); if (0==strnicmp(strName,"joint_",6)) { bIsJoint = true; } BOOL bHasGeometry = false; for (int x=0;(xNumberOfChildren())&&(!bHasGeometry);x++) { CString strChildName = pNode->GetChildNode(x)->GetName(); if (0!=strnicmp(strChildName,"joint_",6)) //if (0!=strnicmp(strChildName,"handle_",7)) bHasGeometry = true; } if (bIsJoint && bHasGeometry) bValid = true; } else { CString strName = pNode->GetName(); if (0!=strnicmp(strName,"cv_",3)) { bValid = bIsJoint = true; } } if (bIsJoint) AddCvNode(pNode,bValid); for (int x=0;xNumberOfChildren();x++) { AddCv(pNode->GetChildNode(x),bCheckName); } } void CvToolPanel::AddCvNode(INode *pNode,BOOL bValid) { if (!bValid) return; /* ******************************* Code from the Max SDK solution #1981 **********************************/ // Create a new object through the CreateInstance() API Object *obj = (Object*)ip->CreateInstance( HELPER_CLASS_ID, CVOBJECT_CLASS_ID); assert(obj); // Get a hold of the parameter block IParamArray *iParams = obj->GetParamBlock(); assert(iParams); // Set the parameters // Set to a default material iParams->SetValue(CV_MATERIAL,TimeValue(0),bValid?MechWarrior4::SteelMaterial:MechWarrior4::MaterialCount); // Set the initial size to the size of the node's bounding box Box3 box; if (bValid) { Object *pObj = pNode->GetObjectRef(); if (pObj) { pObj->GetLocalBoundBox(TimeValue(0),pNode,ip->GetActiveViewport(),box); box = Box3(Point3(0.0,0.0,0.0),box.Width()); for (int x=0;xNumberOfChildren();x++) { Box3 newbox; INode *pChild = pNode->GetChildNode(x); if (0!=strnicmp(pChild->GetName(),"site_",5)) { pChild->GetObjectRef()->GetLocalBoundBox(TimeValue(0),pChild,ip->GetActiveViewport(),newbox); box += Box3(Point3(0.0,0.0,0.0),newbox.Width()); } } if (box.IsEmpty()) box = Box3(Point3(1,1,1),Point3(1,1,1)); } } else box = Box3(Point3(0,0,0),Point3(0,0,0)); // Swap the y and z for some reason Point3 pt = box.Width(); iParams->SetValue(CV_SIZE,TimeValue(0),Point3(pt.x,pt.z,pt.y)); // Create a node in the scene that references the object INode *node = ip->CreateObjectNode(obj); // Name the node and make the name unique. CString strName = pNode->GetName(); if (strnicmp(strName,"joint_",6)==0) { strName = strName.Right(strName.GetLength()-6); } CString rcName; rcName.LoadString(IDS_DB_CVOBJECT); strName = rcName+strName; TSTR name(_T(strName)); ip->MakeNameUnique(name); node->SetName(name); // Add node to the heiarchy and move it to the parent's position pNode->AttachChild(node,0); // Eval the node's object (exclude WSMs) Object *oldObj = node->GetObjectRef(); ObjectState os = oldObj->Eval(ip->GetTime()); // Set the result to be the node's new object (make a clone) Object *newobj = (Object*)os.obj->Clone(); newobj->SetSubSelState(0); // Reset the selection level to object level oldObj->SetAFlag(A_LOCK_TARGET); node->SetObjectRef(newobj); node->NotifyDependents(FOREVER,0,REFMSG_SUBANIM_STRUCTURE_CHANGED); oldObj->ClearAFlag(A_LOCK_TARGET); oldObj->MaybeAutoDelete(); } #endif void CvToolPanel::BuildCollisionVolume(INode *inode) { if (inode == NULL) return; CString nodename = inode->GetName(); nodename.MakeLower(); if (nodename.Find("cv_")>=0 || nodename.Find("light")>=0) return; // depth first so I don't see my new child of the collision box for (int c = 0; c < inode->NumberOfChildren(); c++) { BuildCollisionVolume(inode->GetChildNode(c)); } // add a collision volume for myself // if I am a joint and have a child with geometry... SClass_ID SCID; Class_ID CID; ObjectState os; os = inode->EvalWorldState(0); if (os.obj) { SCID = os.obj->SuperClassID(); CID = os.obj->ClassID(); if (SCID == GEOMOBJECT_CLASS_ID) { theHold.Begin(); Object *obj = (Object*)m_ip->CreateInstance(HELPER_CLASS_ID, CVOBJECT_CLASS_ID); Check_Pointer(obj); // Get a hold of the parameter block IParamArray *iParams = obj->GetParamBlock(); Check_Pointer(iParams); // Set the parameters // Set to a default material iParams->SetValue(CV_MATERIAL,TimeValue(0),Adept::SteelMaterial); // Create the cv node INode *new_node = m_ip->CreateObjectNode(obj); // Figure out the cv name { CString nodename = inode->GetName(); int index = nodename.Find("_",0); if (index >=0) nodename.Delete(0,index+1); CString name = "cv_"; name += nodename; new_node->SetName(name.GetBuffer(50)); } TriObject *meshData; Verify(os.obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))); meshData = (TriObject *) os.obj->ConvertToType(0,Class_ID(TRIOBJ_CLASS_ID, 0)); meshData->mesh.buildBoundingBox(); Box3 box; box = meshData->mesh.getBoundingBox(); Point3 pt = box.Width(); iParams->SetValue(CV_SIZE,TimeValue(0),pt); // figure out the correct offset Point3 offset; offset.x = box.pmin.x - (pt.x*-0.5f); offset.y = box.pmin.y - (pt.y*-0.5f); offset.z = box.pmin.z - (pt.z*-0.5f); Point3 offset_trans = inode->GetObjOffsetPos(); Quat offset_rot = inode->GetObjOffsetRot(); //SPEW(("jerryeds", "obj-'%s'", inode->GetName())); //SPEW(("jerryeds", "qpvt - %f %f %f %f", offset_rot.x, offset_rot.y, offset_rot.z, offset_rot.w)); //SPEW(("jerryeds", "pvt - %f %f %f", offset_trans.x, offset_trans.y, offset_trans.z)); //SPEW(("jerryeds", "pmin - %f %f %f", box.pmin.x, box.pmin.y, box.pmin.z)); //SPEW(("jerryeds", "pmax - %f %f %f", box.pmax.x, box.pmax.y, box.pmax.z)); //SPEW(("jerryeds", "pt - %f %f %f", pt.x, pt.y, pt.z)); //SPEW(("jerryeds", "ofst - %f %f %f", offset.x, offset.y, offset.z)); offset.x += offset_trans.x; offset.y += offset_trans.y; offset.z += offset_trans.z; // Set transformation for the cv node Matrix3 node_tm; node_tm.IdentityMatrix(); offset_rot.MakeMatrix(node_tm); node_tm.SetTrans(offset); new_node->SetNodeTM(0,node_tm); //find nearest joint_ parent node.. INode *closest_parent = FindParentJoint(inode); if (closest_parent) { Check_Pointer(closest_parent); closest_parent->AttachChild(new_node,0); //SPEW(("jerryeds", "par-'%s'", closest_parent->GetName())); } theHold.Accept(0); } } } INode *CvToolPanel::FindParentJoint(INode *inode) { if (inode == NULL) return NULL; if (!strnicmp("joint_", inode->GetName(), 6)) { //SPEW(("jerryeds", "FOUND - '%s'", inode->GetName())); return inode; } else { //SPEW(("jerryeds", "DEEPER - '%s'", inode->GetName())); return FindParentJoint(inode->GetParentNode()); } //SPEW(("jerryeds", "END OF CHAIN - '%s'", inode->GetName())); return NULL; }