Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
442 lines
12 KiB
C++
442 lines
12 KiB
C++
//===========================================================================//
|
|
// 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;(x<pNode->NumberOfChildren())&&(!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;x<pNode->NumberOfChildren();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;x<pNode->NumberOfChildren();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;
|
|
|
|
} |