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.
1410 lines
38 KiB
C++
1410 lines
38 KiB
C++
//===========================================================================//
|
|
// File: SkeletonVerify.cpp
|
|
// Project: MechWarrior 4
|
|
// Contents: Plugin to verify mech skeletons
|
|
//---------------------------------------------------------------------------//
|
|
// 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 "SkeletonVerify.hpp"
|
|
#include "MaxProxies\MaxProxyHeaders.hpp"
|
|
#include "errordlg.h"
|
|
#include <Stuff\StuffHeaders.hpp>
|
|
#include <adept\collisionvolume.hpp>
|
|
#include "cvexport.h"
|
|
#include "animationsuite.h"
|
|
#include "exportUtil.h"
|
|
#include <GameOS\ToolOS.hpp>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// ProtoTypes
|
|
#define FLOAT_EPSILON 0.00001f // (FLOAT)0.0 is close to this
|
|
|
|
enum ERR_ENUM {
|
|
ERR_INVALIDNODE = 1,
|
|
ERR_INVALIDCHILD,
|
|
ERR_NOZEROROOTPOSITION,
|
|
ERR_NOZEROROTATION,
|
|
ERR_NOJOINTWORLD,
|
|
ERR_HASSCALE,
|
|
ERR_NOPLUGINS,
|
|
ERR_DATAERRORS
|
|
};
|
|
|
|
int VerifyCallbackFn(int,INode *,LPVOID);
|
|
int g_maxTextSize;
|
|
|
|
|
|
extern void ConstructCVs(Interface* ip,
|
|
MaxCollisionVolume **pSolidCv,
|
|
MaxCollisionVolume **pHierarchicalCv,
|
|
bool bSuppressPrompts,
|
|
bool bRemapMaterial);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Global Variables
|
|
SkeletonVerifyPanel g_skeletonVerifyPanel;
|
|
CMapStringToOb g_mapJoints; // Maps a string to a CStringList - used for verifying models
|
|
CMapStringToOb g_mapJoints_Compare; // Maps a string to CStringList - used for comparing models
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// SkeletonVerifyPanel Dialog Procedure to handle User and System Interactions
|
|
static BOOL CALLBACK SkeletonVerifyPanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_QUICKFILE_BEGIN:
|
|
{
|
|
//g_skeletonVerifyPanel.Init(hWnd);
|
|
SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_RESETCONTENT,0,0);
|
|
SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_SETHORIZONTALEXTENT,300,0);
|
|
break;
|
|
}
|
|
case WM_QUICKFILE_END:
|
|
{
|
|
g_skeletonVerifyPanel.m_ip->ForceCompleteRedraw();
|
|
break;
|
|
}
|
|
case WM_QUICKFILE_APPLYFILE:
|
|
{
|
|
char *name = (char *)wParam;
|
|
char *path = (char *)lParam;
|
|
|
|
g_skeletonVerifyPanel.m_ip->LoadFromFile(path);
|
|
// g_skeletonVerifyPanel.m_ip->ForceCompleteRedraw();
|
|
int iCheck = SendDlgItemMessage(hWnd,IDC_CHECK_COMPARE,BM_GETCHECK,0,0);
|
|
if (BST_CHECKED == iCheck)
|
|
{
|
|
int status = g_skeletonVerifyPanel.SkeletonCompare(VerifyCallbackFn,(LPVOID)GetDlgItem(hWnd,IDC_SKELETONVERIFY_LISTBOX));
|
|
}
|
|
else
|
|
{
|
|
int status = g_skeletonVerifyPanel.SkeletonVerify(VerifyCallbackFn,(LPVOID)GetDlgItem(hWnd,IDC_SKELETONVERIFY_LISTBOX));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_INITDIALOG: //Panel's extra initialization
|
|
g_skeletonVerifyPanel.Init(hWnd);
|
|
break;
|
|
case WM_DESTROY: //Panel's extra destruction
|
|
g_skeletonVerifyPanel.Destroy(hWnd);
|
|
break;
|
|
case WM_COMMAND :
|
|
{ //Handle Panel's controls
|
|
HWND hwndCtrl = (HWND)lParam;
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_CHECKEXPORT:
|
|
{
|
|
g_skeletonVerifyPanel.OnErrorCheck(VerifyCallbackFn);
|
|
break;
|
|
}
|
|
case IDC_CHECK_COMPARE:
|
|
{
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case BN_CLICKED:
|
|
{
|
|
int iCheck = SendMessage(hwndCtrl,BM_GETCHECK,0,0);
|
|
if (BST_CHECKED == iCheck)
|
|
{
|
|
SetWindowText(GetDlgItem(hWnd,IDC_SKELETONVERIFY_EXECUTE),"Compare");
|
|
}
|
|
else
|
|
{
|
|
SetWindowText(GetDlgItem(hWnd,IDC_SKELETONVERIFY_EXECUTE),"Verify");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case IDC_SKELETONVERIFY_COMPARE:
|
|
{
|
|
CFileDialog fd(TRUE,NULL,NULL,0,"Max Files (*.max)|*.max||",CWnd::FromHandle(hWnd));
|
|
char *filebuf = new char[MAX_PATH*200];
|
|
filebuf[0] = 0;
|
|
fd.m_ofn.lpstrFile = filebuf;
|
|
fd.m_ofn.nMaxFile = MAX_PATH*200;
|
|
if (fd.DoModal()==IDOK)
|
|
{
|
|
CString path = fd.GetPathName();
|
|
char fname[20];
|
|
_splitpath((LPCTSTR)path,NULL,NULL,fname,NULL);
|
|
g_skeletonVerifyPanel.m_ip->LoadFromFile(path);
|
|
g_skeletonVerifyPanel.m_ip->ForceCompleteRedraw();
|
|
|
|
EnableWindow(GetDlgItem(hWnd,IDC_CHECK_COMPARE),true);
|
|
CString str;
|
|
str.Format("Compare to: %s",fname);
|
|
SetDlgItemText(hWnd,IDC_CHECK_COMPARE,str);
|
|
SendDlgItemMessage(hWnd,IDC_CHECK_COMPARE,BM_SETCHECK,BST_CHECKED,0);
|
|
|
|
SetWindowText(GetDlgItem(hWnd,IDC_SKELETONVERIFY_EXECUTE),"Compare");
|
|
|
|
g_skeletonVerifyPanel.InitCompareMap();
|
|
}
|
|
|
|
break;
|
|
}
|
|
case IDC_QUICKFILE_LISTBOX:
|
|
{
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case LBN_SELCHANGE:
|
|
{
|
|
HWND hListBox = (HWND)lParam;
|
|
|
|
int index = SendMessage(hListBox,LB_GETCURSEL,0,0);
|
|
char *path = (char *)SendMessage(hListBox,LB_GETITEMDATA,index,0);
|
|
|
|
SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_RESETCONTENT,0,0);
|
|
SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_SETHORIZONTALEXTENT,300,0);
|
|
g_skeletonVerifyPanel.m_ip->LoadFromFile(path);
|
|
g_skeletonVerifyPanel.m_ip->ForceCompleteRedraw();
|
|
|
|
int iCheck = SendDlgItemMessage(hWnd,IDC_CHECK_COMPARE,BM_GETCHECK,0,0);
|
|
if (BST_CHECKED == iCheck)
|
|
{
|
|
int status = g_skeletonVerifyPanel.SkeletonCompare(VerifyCallbackFn,(LPVOID)GetDlgItem(hWnd,IDC_SKELETONVERIFY_LISTBOX));
|
|
}
|
|
else
|
|
{
|
|
//g_skeletonVerifyPanel.Init(hWnd);
|
|
int status = g_skeletonVerifyPanel.SkeletonVerify(VerifyCallbackFn,(LPVOID)GetDlgItem(hWnd,IDC_SKELETONVERIFY_LISTBOX));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case IDC_ABOUT: {
|
|
CAbout dlg;
|
|
dlg.DoModal();
|
|
break;}
|
|
case IDC_SKELETONVERIFY_EXECUTE:
|
|
{
|
|
SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_RESETCONTENT,0,0);
|
|
SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_SETHORIZONTALEXTENT,300,0);
|
|
g_maxTextSize = 0;
|
|
int iCheck = SendDlgItemMessage(hWnd,IDC_CHECK_COMPARE,BM_GETCHECK,0,0);
|
|
if (BST_CHECKED == iCheck)
|
|
{
|
|
int status = g_skeletonVerifyPanel.SkeletonCompare(VerifyCallbackFn,(LPVOID)GetDlgItem(hWnd,IDC_SKELETONVERIFY_LISTBOX));
|
|
}
|
|
else
|
|
{
|
|
//g_skeletonVerifyPanel.Init(hWnd);
|
|
int status = g_skeletonVerifyPanel.SkeletonVerify(VerifyCallbackFn,(LPVOID)GetDlgItem(hWnd,IDC_SKELETONVERIFY_LISTBOX));
|
|
}
|
|
//SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_SETHORIZONTALEXTENT,g_maxTextSize,0);
|
|
//MessageBox(hWnd,"Skeleton Verification Complete","Skeleton Verify",MB_OK);
|
|
break;
|
|
}
|
|
case IDC_SKELETONVERIFY_LISTBOX:
|
|
{
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case LBN_SELCHANGE:
|
|
{
|
|
g_skeletonVerifyPanel.HandleSelChange(hwndCtrl);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//The following lines are not necessary for MAX2 Plugins
|
|
case WM_LBUTTONDOWN:
|
|
case WM_LBUTTONUP:
|
|
case WM_MOUSEMOVE:
|
|
g_skeletonVerifyPanel.m_ip->RollupMouseMessage(hWnd, msg, wParam, lParam);
|
|
break;
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Display the Plugin's Panel
|
|
void SkeletonVerifyPanel::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 = m_ip->AddRollupPage(loc_hInstance, MAKEINTRESOURCE(IDD_SKELETONVERIFY_PANEL),
|
|
SkeletonVerifyPanelProc, GetString(IDS_SKELETONVERIFY_NAME),0);
|
|
|
|
m_hQuickFile = EnableQuickFile(m_ip,m_hPanel);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Free the Plugins' Panel
|
|
void SkeletonVerifyPanel::EndEditParams(Interface *ip, IUtil *iu)
|
|
{
|
|
DisableQuickFile(ip,m_hQuickFile);
|
|
m_iu = NULL;
|
|
m_ip = NULL;
|
|
|
|
//Remove the Rollup Dialog
|
|
ip->DeleteRollupPage(m_hPanel);
|
|
m_hPanel = NULL;
|
|
}
|
|
|
|
// first word is the parent, the rest is the list of children
|
|
char g_szJointMap[][100] =
|
|
{
|
|
"joint_WORLD joint_VEL handle_rfoot handle_lfoot",
|
|
"joint_VEL joint_ROOT",
|
|
"joint_ROOT joint_luleg joint_ruleg joint_hipbelow",
|
|
"joint_luleg joint_lmleg joint_ldleg luleg",
|
|
"joint_lmleg joint_ldleg",
|
|
"joint_ldleg joint_lankle site_ldjetport site_lfoot",
|
|
"joint_lankle joint_ltoe joint_lftoe joint_lbtoe joint_litoe joint_lotoe lfoot site_lfoot",
|
|
"joint_ruleg joint_rmleg joint_rdleg ruleg",
|
|
"joint_rmleg joint_rdleg",
|
|
"joint_rdleg joint_rankle site_rdjetport site_rfoot",
|
|
"joint_rankle joint_rtoe joint_rftoe joint_rbtoe joint_ritoe joint_rotoe rfoot site_rfoot",
|
|
"joint_hipbelow joint_hip",
|
|
"joint_hip joint_hipabove joint_torso",
|
|
"joint_hipabove joint_torsobelow hip",
|
|
"joint_torsobelow joint_torso",
|
|
"joint_torso joint_luarm joint_ruarm joint_torsoabove",
|
|
|
|
"joint_torsoabove joint_head joint_centertorsofront joint_centertorsorear",
|
|
"joint_torsoabove joint_righttorsofront joint_lefttorsofront",
|
|
"joint_torsoabove joint_luarmabove joint_ruarmabove joint_missile torso site_eyepoint",
|
|
"joint_torsoabove site_eject site_light site_radar site_coolantflush site_lmissileport",
|
|
"joint_torsoabove site_rmissileport site_missileport site_lexhaust site_rexhaust site_exhaust",
|
|
"joint_torsoabove site_rujetport site_lujetport site_torsoport site_ltorsoport site_lutorsoport",
|
|
"joint_torsoabove site_ldtorsoport site_rtorsoport site_rutorsoport site_rdtorsoport",
|
|
"joint_torsoabove joint_cage joint_lmissile joint_rmissile",
|
|
"joint_torsoabove site_jcattach site_jcjetport01 site_jcjetport02 site_jcjetport03 site_jcjetport04",
|
|
"joint_cage site_cageleft site_cageright site_light",
|
|
|
|
"joint_luarmabove joint_luarm",
|
|
"joint_ruarmabove joint_ruarm",
|
|
"joint_luarm joint_lmarm joint_lgunabove joint_lgun luarm",
|
|
"joint_lmarm joint_ldarm",
|
|
"joint_ldarm joint_lgunabove",
|
|
"joint_lgunabove joint_lgun",
|
|
"joint_ruarm joint_rmarm joint_rgunabove joint_rgun ruarm",
|
|
"joint_rmarm joint_rdarm",
|
|
"joint_rdarm joint_rgunabove",
|
|
"joint_rgunabove joint_rgun",
|
|
|
|
"joint_lgun site_ldgunport site_lugunport site_lgunport site_lshellport site_logunport",
|
|
"joint_lgun site_ligunport site_lgunexhaust lgun",
|
|
"joint_rgun site_rdgunport site_rugunport site_rgunport site_rshellport site_rogunport",
|
|
"joint_rgun site_rdgunport site_rgunexhaust rgun",
|
|
"joint_missile missile site_exhaust site_missileport",
|
|
|
|
"joint_righttorsofront site_rmissileport site_rtorsoport site_rdtorsoport site_rujetport",
|
|
"joint_lefttorsofront site_lmissileport site_ltorsoport site_ldtorsoport site_lujetport",
|
|
"joint_head site_lutorsoport",
|
|
"joint_centertorsofront site_ldtorsoport",
|
|
"joint_specialone",
|
|
"joint_specialtwo"};
|
|
|
|
// These are the valid geometry names
|
|
char g_szGeomSuffix[] =
|
|
"lgun luarm rgun ruarm torso hip rftoe ritoe rotoe rfoot rdleg ruleg \
|
|
lftoe litoe lotoe lfoot ldleg luleg rmleg lmleg lbtoe rbtoe ltoe rtoe \
|
|
runninglights searchlight specialone specialtwo \
|
|
Team_Left Team_Right Pilot_Left Pilot_Right";
|
|
|
|
// These are the joints that should have 0 world state rotation
|
|
char g_szJointNoRotate[] = "WORLD hipbelow hipabove torsobelow torsoabove ruarmabove luarmabove rgunabove lgunabove";
|
|
CStringList g_listJointNoRotate;
|
|
CStringList g_listGeomSuffix;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Panel Initialization callback
|
|
void SkeletonVerifyPanel::Init(HWND hWnd)
|
|
{
|
|
|
|
HWND hList = GetDlgItem(hWnd,IDC_SKELETONVERIFY_LISTBOX);
|
|
LONG lStyle = GetWindowLong(hList,GWL_STYLE);
|
|
lStyle |= WS_HSCROLL;
|
|
SetWindowLong(hList,GWL_STYLE,lStyle);
|
|
|
|
// Initialize the map
|
|
{
|
|
for (int x=0;x<(sizeof(g_szJointMap)/100);x++)
|
|
{
|
|
char szData[100];
|
|
strcpy(szData,g_szJointMap[x]);
|
|
char *pname = strtok(szData," ");
|
|
if (pname)
|
|
{
|
|
|
|
CString strName = CString(pname);
|
|
strName.MakeLower();
|
|
CStringList *pList;
|
|
if (g_mapJoints[strName])
|
|
pList = (CStringList *)g_mapJoints[strName];
|
|
else
|
|
g_mapJoints[strName] = pList = new CStringList;
|
|
while (char *p = strtok(NULL," "))
|
|
{
|
|
CString str1 = CString(p);
|
|
str1.MakeLower();
|
|
pList->AddTail(str1);
|
|
if (!g_mapJoints[str1])
|
|
g_mapJoints[str1] = new CStringList;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Initialize the zero rotation list
|
|
{
|
|
g_listJointNoRotate.RemoveAll();
|
|
char *dup = strdup(g_szJointNoRotate);
|
|
char *str = strtok(dup," ");
|
|
while (str)
|
|
{
|
|
g_listJointNoRotate.AddTail(CString("joint_")+CString(str));
|
|
str = strtok(NULL," ");
|
|
}
|
|
delete dup;
|
|
}
|
|
|
|
//Initialize the geometry names
|
|
{
|
|
g_listGeomSuffix.RemoveAll();
|
|
char *dup = strdup(g_szGeomSuffix);
|
|
char *str = strtok(dup," ");
|
|
while (str)
|
|
{
|
|
CString name(str);
|
|
name.MakeLower();
|
|
g_listGeomSuffix.AddTail(name);
|
|
str = strtok(NULL," ");
|
|
}
|
|
delete dup;
|
|
}
|
|
// Initialize the compare map if a model is currently loaded
|
|
{
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Panel Destruction callback
|
|
void SkeletonVerifyPanel::Destroy(HWND hWnd)
|
|
{
|
|
//destroy the map list pointer data
|
|
{
|
|
POSITION pos = g_mapJoints.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
CString str;
|
|
CObject *pObj;
|
|
g_mapJoints.GetNextAssoc(pos,str,pObj);
|
|
str.MakeLower();
|
|
CStringList *pList = (CStringList *)pObj;
|
|
pList->RemoveAll();
|
|
delete pList;
|
|
}
|
|
g_mapJoints.RemoveAll();
|
|
|
|
pos = g_mapJoints_Compare.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
CString str;
|
|
CObject *pObj;
|
|
g_mapJoints_Compare.GetNextAssoc(pos,str,pObj);
|
|
str.MakeLower();
|
|
CStringList *pList = (CStringList *)pObj;
|
|
pList->RemoveAll();
|
|
delete pList;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Functions
|
|
int SkeletonVerifyPanel::SkeletonVerify(LPSKELETONVERIFY_CALLBACKFN pFn,LPVOID lpVoid)
|
|
{
|
|
// INode *pRoot = m_ip->GetRootNode();
|
|
INode *pRoot = m_ip->GetINodeByName("joint_WORLD");
|
|
|
|
if (NULL == pRoot)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_NOJOINTWORLD,pRoot,lpVoid);
|
|
else
|
|
MessageBox(NULL,"joint_WORLD not found","World Node error",MB_OK);
|
|
return 0;
|
|
}
|
|
// Check for world position at 0,0,0
|
|
{
|
|
// Point3 offset = pRoot->GetObjOffsetPos();
|
|
Matrix3 mat = pRoot->GetObjTMAfterWSM(0);
|
|
Point3 offset = mat.GetTrans();
|
|
if ((offset.x != 0.0) && (offset.y != 0.0) && (offset.z != 0.0))
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_NOZEROROOTPOSITION,pRoot,lpVoid);
|
|
else
|
|
MessageBox(NULL,"Root not positioned at 0","Root Node error",MB_OK);
|
|
}
|
|
}
|
|
|
|
// Verify the joint hiearchy
|
|
{
|
|
int status = VerifyNode(pRoot,pFn,lpVoid);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int SkeletonVerifyPanel::VerifyNode(INode *pNode,LPSKELETONVERIFY_CALLBACKFN pFn,LPVOID lpVoid)
|
|
{
|
|
int status = 0;
|
|
|
|
CString strName(pNode->GetName());
|
|
strName.MakeLower();
|
|
CStringList *pList = (CStringList *)g_mapJoints[strName];
|
|
if (NULL == pList)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_INVALIDNODE,pNode,lpVoid);
|
|
else
|
|
{
|
|
CString str = "Invalid node naming: "+strName;
|
|
MessageBox(NULL,str,"Node error",MB_OK);
|
|
}
|
|
// Invalid node strName
|
|
return 1;
|
|
}
|
|
|
|
//Verify that the node has no rotation if it is not supposed to
|
|
{
|
|
if (g_listJointNoRotate.Find(strName))
|
|
{
|
|
Matrix3 mat = pNode->GetObjTMAfterWSM(0);
|
|
bool isrot = FALSE;
|
|
float val;
|
|
for (int x = 0;x<3;x++)
|
|
for (int y = 0;y<3;y++)
|
|
if (x==y)
|
|
{
|
|
if (FLOAT_EPSILON <= ((val = mat.GetRow(x)[y])-1.0f))
|
|
isrot = TRUE;
|
|
}
|
|
else
|
|
if (FLOAT_EPSILON <= fabs(val = mat.GetRow(x)[y]))
|
|
isrot =TRUE;
|
|
|
|
if (isrot)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_NOZEROROTATION,pNode,lpVoid);
|
|
else
|
|
MessageBox(NULL,"Node requires zero rotation","Node error",MB_OK);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Verify that the node has no scale if it is not supposed to
|
|
{
|
|
Matrix3 parentTM, nodeTM, localTM;
|
|
nodeTM = pNode->GetNodeTM(0);
|
|
parentTM = pNode->GetParentTM(0);
|
|
localTM = nodeTM*Inverse(parentTM);
|
|
|
|
AffineParts ap;
|
|
decomp_affine(localTM, &ap);
|
|
Point3 s = ap.k;
|
|
BOOL bError = false;
|
|
for (int x=0;x<3;x++)
|
|
if (fabs(s[x]-1.0)>0.00001)
|
|
bError = true;
|
|
if (bError)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_HASSCALE,pNode,lpVoid);
|
|
else
|
|
MessageBox(NULL,"Node requires zero scale","Node error",MB_OK);
|
|
}
|
|
}
|
|
for (int x=0;x<pNode->NumberOfChildren();x++)
|
|
{
|
|
INode *pChild = pNode->GetChildNode(x);
|
|
CString strChildName(pChild->GetName());
|
|
strChildName.MakeLower();
|
|
strChildName.Replace(" ", "");
|
|
|
|
if (pList->Find(strChildName,NULL))
|
|
{
|
|
status |= VerifyNode(pChild,pFn,lpVoid);
|
|
}
|
|
else
|
|
{
|
|
CString geoName = strChildName;
|
|
int n = strChildName.Find("_", 1);
|
|
if (n>0)
|
|
geoName = strChildName.Right(strChildName.GetLength()-n-1);
|
|
|
|
if (g_listGeomSuffix.Find(geoName) ||
|
|
strChildName.Find("cv_")>=0)
|
|
{
|
|
// This is a piece of geometry, or CV
|
|
// ignore the name_ (prefix) and don't check chidlren
|
|
}
|
|
else
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_INVALIDCHILD,pChild,lpVoid);
|
|
else
|
|
{
|
|
CString str = "Invalid child of "+strName+" : "+strChildName;
|
|
MessageBox(NULL,str,"Node error",MB_OK);
|
|
}
|
|
// pChild is not a valid child of pNode
|
|
status |= 2;
|
|
}
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static int VerifyCallbackFn(int status,INode *pNode,LPVOID lpVoid)
|
|
{
|
|
HWND hWnd = (HWND)lpVoid;
|
|
char str[100];
|
|
switch (status)
|
|
{
|
|
case ERR_INVALIDNODE:
|
|
{
|
|
strcpy(str,"Invalid Node Naming");
|
|
break;
|
|
}
|
|
case ERR_INVALIDCHILD:
|
|
{
|
|
INode *pParent = pNode->GetParentNode();
|
|
if (pParent)
|
|
sprintf(str,"(%s) ",pParent->GetName());
|
|
strcat(str,"Invalid Child Node");
|
|
break;
|
|
}
|
|
case ERR_NOZEROROOTPOSITION:
|
|
{
|
|
strcpy(str,"Root Position not (0,0,0)");
|
|
break;
|
|
}
|
|
case ERR_NOZEROROTATION:
|
|
{
|
|
strcpy(str,"Requires Zero Rotation");
|
|
break;
|
|
}
|
|
case ERR_NOJOINTWORLD:
|
|
{
|
|
strcpy(str,"joint_WORLD node not found");
|
|
break;
|
|
}
|
|
case ERR_HASSCALE:
|
|
{
|
|
strcpy(str,"Node has scale");
|
|
break;
|
|
}
|
|
case ERR_NOPLUGINS:
|
|
{
|
|
strcpy(str,"Plugins.ini not found");
|
|
}
|
|
case ERR_DATAERRORS:
|
|
{
|
|
strcpy(str,"Found geometry data errors");
|
|
}
|
|
default:
|
|
{
|
|
}
|
|
}
|
|
char errstr[100];
|
|
sprintf(errstr,"%-20s - %s",pNode?pNode->GetName():"NULL",str);
|
|
int index = SendMessage(hWnd,LB_ADDSTRING,NULL,(LPARAM)errstr);
|
|
SIZE size;
|
|
HDC hDC = GetDC(hWnd);
|
|
GetTextExtentPoint32(hDC,errstr,strlen(errstr),&size);
|
|
ReleaseDC(hWnd,hDC);
|
|
//int width = SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_GETHORIZONTALEXTENT,0,0);
|
|
if (g_maxTextSize < size.cx)
|
|
g_maxTextSize = size.cx;
|
|
//SendDlgItemMessage(hWnd,IDC_SKELETONVERIFY_LISTBOX,LB_SETHORIZONTALEXTENT,size.cx,0);
|
|
SendMessage(hWnd,LB_SETITEMDATA,index,(LPARAM)pNode);
|
|
return 0;
|
|
}
|
|
|
|
// When the ListBox control recieves a selchange notification message, handle
|
|
int SkeletonVerifyPanel::HandleSelChange(HWND hWnd)
|
|
{
|
|
int selcount = SendMessage(hWnd,LB_GETSELCOUNT,0,0);
|
|
if (selcount>0)
|
|
{
|
|
int *selarray = new int[selcount];
|
|
int result = SendMessage(hWnd,LB_GETSELITEMS,selcount,(LPARAM)selarray);
|
|
// result should be equal to selcount
|
|
|
|
m_ip->ClearNodeSelection(FALSE);
|
|
for (int x=0;x<selcount;x++)
|
|
{
|
|
INode *pNode = (INode *)SendMessage(hWnd,LB_GETITEMDATA,selarray[x],0);
|
|
if (pNode)
|
|
{
|
|
m_ip->SelectNode(pNode,FALSE);
|
|
}
|
|
}
|
|
m_ip->ForceCompleteRedraw();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int SkeletonVerifyPanel::AddNode(INode *pNode)
|
|
{
|
|
if (pNode == NULL)
|
|
return 1;
|
|
CStringList *pList;
|
|
CString strName = pNode->GetName();
|
|
strName.MakeLower();
|
|
|
|
if (g_mapJoints_Compare[strName])
|
|
pList = (CStringList *)g_mapJoints_Compare[strName];
|
|
else
|
|
g_mapJoints_Compare[strName] = pList = new CStringList;
|
|
|
|
for (int x=0;x<pNode->NumberOfChildren();x++)
|
|
{
|
|
INode *pChild = pNode->GetChildNode(x);
|
|
CString strChild = pChild->GetName();
|
|
strChild.MakeLower();
|
|
pList->AddTail(strChild);
|
|
if (!g_mapJoints_Compare[strChild])
|
|
g_mapJoints_Compare[strChild] = new CStringList;
|
|
AddNode(pChild);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int SkeletonVerifyPanel::InitCompareMap()
|
|
{
|
|
// Duplicate code from the :Destroy
|
|
POSITION pos = g_mapJoints_Compare.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
CString str;
|
|
CObject *pObj;
|
|
g_mapJoints_Compare.GetNextAssoc(pos,str,pObj);
|
|
str.MakeLower();
|
|
CStringList *pList = (CStringList *)pObj;
|
|
pList->RemoveAll();
|
|
delete pList;
|
|
}
|
|
g_mapJoints_Compare.RemoveAll();
|
|
|
|
// add the joints
|
|
INode *pRoot = m_ip->GetINodeByName("joint_WORLD");
|
|
AddNode(pRoot);
|
|
return 0;
|
|
}
|
|
|
|
int SkeletonVerifyPanel::CompareNode(INode *pNode,LPSKELETONVERIFY_CALLBACKFN pFn,LPVOID lpVoid)
|
|
{
|
|
int status = 0;
|
|
|
|
CString strName(pNode->GetName());
|
|
CStringList *pList = (CStringList *)g_mapJoints_Compare[strName];
|
|
if (NULL == pList)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_INVALIDNODE,pNode,lpVoid);
|
|
else
|
|
{
|
|
CString str = "Invalid node naming: "+strName;
|
|
MessageBox(NULL,str,"Node naming error",MB_OK);
|
|
}
|
|
// Invalid node strName
|
|
return 1;
|
|
}
|
|
|
|
//Verify that the node has no rotation if it is not supposed to
|
|
/* {
|
|
if (g_listJointNoRotate.Find(strName))
|
|
{
|
|
Matrix3 mat = pNode->GetObjTMAfterWSM(0);
|
|
bool isrot = FALSE;
|
|
float val;
|
|
for (int x = 0;x<3;x++)
|
|
for (int y = 0;y<3;y++)
|
|
if (x==y)
|
|
{
|
|
if (FLOAT_EPSILON <= ((val = mat.GetRow(x)[y])-1.0f))
|
|
isrot = TRUE;
|
|
}
|
|
else
|
|
if (FLOAT_EPSILON <= fabs(val = mat.GetRow(x)[y]))
|
|
isrot =TRUE;
|
|
|
|
if (isrot)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_NOZEROROTATION,pNode,lpVoid);
|
|
else
|
|
MessageBox(NULL,"Node requires zero rotation","Node error",MB_OK);
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
for (int x=0;x<pNode->NumberOfChildren();x++)
|
|
{
|
|
INode *pChild = pNode->GetChildNode(x);
|
|
CString strChildName(pChild->GetName());
|
|
if (pList->Find(strChildName,NULL))
|
|
{
|
|
status |= CompareNode(pChild,pFn,lpVoid);
|
|
}
|
|
else
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_INVALIDCHILD,pChild,lpVoid);
|
|
else
|
|
{
|
|
CString str = strChildName+"is not a valid child of "+strName;
|
|
MessageBox(NULL,str,"Node error",MB_OK);
|
|
}
|
|
// pChild is not a valid child of pNode
|
|
status |= 2;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
int SkeletonVerifyPanel::CheckCv(INode *pNode)
|
|
{
|
|
int err = 0;
|
|
CString name = pNode->GetName();
|
|
if (strnicmp(name,"cv_",3)==0)
|
|
{
|
|
// Check that it is a cv node class
|
|
Object *pObj = pNode->GetObjectRef();
|
|
if (pObj && (pObj->ClassID() != CVOBJECT_CLASS_ID))
|
|
{
|
|
CString str;
|
|
str.Format("%s is not a collision volume",name);
|
|
ReportError(str);
|
|
err++;
|
|
}
|
|
}
|
|
int count = pNode->NumberOfChildren();
|
|
for (int x=0;x>count;x++)
|
|
err+= CheckCv(pNode->GetChildNode(x));
|
|
return err;
|
|
}
|
|
|
|
int SkeletonVerifyPanel::SkeletonCompare(LPSKELETONVERIFY_CALLBACKFN pFn,LPVOID lpVoid)
|
|
{
|
|
// INode *pRoot = m_ip->GetRootNode();
|
|
INode *pRoot = m_ip->GetINodeByName("joint_WORLD");
|
|
|
|
if (NULL == pRoot)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_NOJOINTWORLD,pRoot,lpVoid);
|
|
else
|
|
MessageBox(NULL,"joint_WORLD not found","World Node error",MB_OK);
|
|
}
|
|
// Check for world position at 0,0,0
|
|
/* {
|
|
Matrix3 mat = pRoot->GetObjTMAfterWSM(0);
|
|
Point3 offset = mat.GetTrans();
|
|
if ((offset.x != 0.0) && (offset.y != 0.0) && (offset.z != 0.0))
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_NOZEROROOTPOSITION,pRoot,lpVoid);
|
|
else
|
|
MessageBox(NULL,"Root not positioned at 0","Root Node error",MB_OK);
|
|
}
|
|
}
|
|
*/
|
|
// Verify the joint hiearchy
|
|
{
|
|
int status = CompareNode(pRoot,pFn,lpVoid);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void SkeletonVerifyPanel::OnErrorCheck(LPSKELETONVERIFY_CALLBACKFN pFn)
|
|
{
|
|
CErrorDlg dlg;
|
|
if (IDOK == dlg.DoModal())
|
|
{
|
|
TSTR maxDataPath = m_ip->GetDir(APP_PLUGCFG_DIR);
|
|
CString ini_path = Stuff::MString(maxDataPath)+"\\PlugIns.ini";
|
|
bool ini_file_exists = gos_DoesFileExist(ini_path);
|
|
|
|
if (!ini_file_exists)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_NOPLUGINS,NULL,(LPVOID)m_ip->GetMAXHWnd());
|
|
else
|
|
ReportError("Plugins.Ini file does not exist");
|
|
}
|
|
|
|
if (dlg.m_bAnim)
|
|
{
|
|
// Recursively - check the nodes
|
|
/*
|
|
JointPreference *prefs = JointEditDialog::GetJointPrefrence(node);
|
|
if(prefs != NULL)
|
|
{
|
|
if (prefs->excludeJoint == JointPreference::IncludeJoint)
|
|
{
|
|
include_joint = true;
|
|
}
|
|
else if (prefs->excludeJoint == JointPreference::AutoJoint)
|
|
{
|
|
if(dialog->NodeAnimated(node))
|
|
{
|
|
include_joint = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Control *tm_controler = node->GetTMController();
|
|
Control *translation_controler = tm_controler->GetPositionController();
|
|
Control *rotation_controler = tm_controler->GetRotationController();
|
|
if (c->ClassID() == Class_ID(LININTERP_POSITION_CLASS_ID,0))
|
|
{
|
|
return MW4Animation::JointAnimData::Point3DLinearKeyType;
|
|
}
|
|
else if (c->ClassID() == Class_ID(LININTERP_ROTATION_CLASS_ID,0))
|
|
{
|
|
return MW4Animation::JointAnimData::QuaternionLinearKeyType;
|
|
}
|
|
|
|
STOP(("INVALID KEY TYPE!!!!!"));
|
|
*/
|
|
}
|
|
|
|
if (dlg.m_bBatch)
|
|
{
|
|
CFileDialog fd(TRUE,NULL,NULL,0,"Batch Files (*.batch)|*.batch||",NULL);
|
|
if (IDOK == fd.DoModal())
|
|
{
|
|
// Check the Batch notation file
|
|
int err = CheckBatch(pFn,m_ip,(char *)(LPCTSTR)fd.GetPathName());
|
|
}
|
|
|
|
// Load the skeleton and save the names of the geometry nodes (mesh nodes)
|
|
// Verify that all Geometry node names in LOD are in skeleton
|
|
}
|
|
|
|
// Check that the OBB file has collision volumes - run skeleton verify too?
|
|
if (dlg.m_bObb)
|
|
{
|
|
int err = CheckCv(m_ip->GetRootNode());
|
|
|
|
// Check that the OBB file has collision volumes - run skeleton verify too?
|
|
// This is the CV exporter code:
|
|
|
|
MaxCollisionVolume *pSolidCv = NULL;
|
|
MaxCollisionVolume *pHierarchicalCv = NULL;
|
|
ConstructCVs(m_ip, &pSolidCv, &pHierarchicalCv);
|
|
|
|
|
|
if (!pSolidCv && !pHierarchicalCv)
|
|
{
|
|
CString str = CString(m_ip->GetCurFileName())+" does not contain any collision volumes.";
|
|
ReportError(str);
|
|
}
|
|
if (pHierarchicalCv)
|
|
delete pHierarchicalCv;
|
|
if (pSolidCv)
|
|
delete pSolidCv;
|
|
}
|
|
|
|
if (dlg.m_bLights)
|
|
{
|
|
// Check that the lights are a valid type
|
|
}
|
|
|
|
// Do this last cuz it loads files
|
|
if (dlg.m_bErf)
|
|
{
|
|
MAXProxies::MAXScene *scene = MAXProxies::MAXScene::MakeProxy(m_ip,"");
|
|
Check_Object(scene);
|
|
|
|
Stuff::NotationFile config_file(ini_path);
|
|
MAXProxies::FindMAXErrors process_errors(&config_file,m_ip,0,false,(LPVOID)&ReportError);
|
|
|
|
int err;
|
|
if (err = scene->FindErrors(&process_errors)> 0)
|
|
{
|
|
if (pFn)
|
|
pFn(ERR_DATAERRORS,NULL,(LPVOID)m_ip->GetMAXHWnd());
|
|
else
|
|
ReportError("Found Data Errors: Verification FAILED!");
|
|
}
|
|
}
|
|
|
|
MessageBox(NULL,"Error Check Done","Check For Errors",MB_OK);
|
|
}
|
|
}
|
|
|
|
static bool SetBit(WORD &flag,int bit)
|
|
{
|
|
WORD val = 1 << bit;
|
|
if (flag & val)
|
|
return true;
|
|
flag &= val;
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
int FindGeometry(CStringList *list,INode *pNode)
|
|
{
|
|
int count =0;
|
|
if(IsNodeGeometry(pNode))
|
|
{
|
|
count ++;
|
|
CString name = pNode->GetName();
|
|
name.MakeLower();
|
|
if (NULL == list->Find(name))
|
|
list->AddHead(name);
|
|
}
|
|
|
|
for (int c = 0; c < pNode->NumberOfChildren(); c++)
|
|
{
|
|
count += FindGeometry(list,pNode->GetChildNode(c)
|
|
}
|
|
return count;
|
|
}
|
|
*/
|
|
|
|
int SkeletonVerifyPanel::CheckBatch(LPSKELETONVERIFY_CALLBACKFN pFn,Interface *m_ip,char *batch_filename)
|
|
{
|
|
Stuff::NotationFile notefile(batch_filename);
|
|
|
|
Stuff::NotationFile::PageIterator *pages = notefile.MakePageIterator();
|
|
Check_Object(pages);
|
|
|
|
Stuff::Page *page;
|
|
|
|
// Enumerate through the pages
|
|
// Each page - look for LODSkel, LODCHAR, LODDAM,OBB, ANIM - that files exist
|
|
// See that there are the same number of LODCHAR as LODDAM
|
|
|
|
while((page = pages->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(page);
|
|
|
|
const char *pagename = page->GetName();
|
|
|
|
CStringList listChar,listDam,listDist,listShape;
|
|
CString path,obb,anim,skel;
|
|
|
|
WORD charFlag=0,damFlag=0,distFlag=0,shapeFlag=0;
|
|
|
|
// Gather Data
|
|
Stuff::Page::NoteIterator *notes = page->MakeNoteIterator();
|
|
Check_Object(notes);
|
|
|
|
Stuff::Note *note;
|
|
// Enumerate the entries in the section
|
|
while ((note = notes->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(note);
|
|
|
|
const char *notename = note->GetName();
|
|
const char *entryname;
|
|
|
|
note->GetEntry(&entryname);
|
|
|
|
/************************/
|
|
// Compile the data
|
|
if (0==stricmp(notename,"path"))
|
|
{
|
|
if (path.GetLength())
|
|
{
|
|
ReportError(CString(pagename)+":"+CString(notename)+" set multiple times.");
|
|
// Error: This was already set
|
|
}
|
|
path = entryname;
|
|
}
|
|
else if (0==stricmp(notename,"anim"))
|
|
{
|
|
if (anim.GetLength())
|
|
{
|
|
// Error: This was already set
|
|
ReportError(CString(pagename)+":"+CString(notename)+" set multiple times.");
|
|
}
|
|
anim = entryname;
|
|
}
|
|
else if (0==stricmp(notename,"obb"))
|
|
{
|
|
if (obb.GetLength())
|
|
{
|
|
// Error: This was already set
|
|
ReportError(CString(pagename)+":"+CString(notename)+" set multiple times.");
|
|
}
|
|
obb = entryname;
|
|
}
|
|
else if (0==stricmp(notename,"LODskel"))
|
|
{
|
|
if (skel.GetLength())
|
|
{
|
|
// Error: This was already set
|
|
ReportError(CString(pagename)+":"+CString(notename)+" set multiple times.");
|
|
}
|
|
skel = entryname;
|
|
}
|
|
else if (0==stricmp(notename,"LODShape"))
|
|
{
|
|
listShape.AddTail(entryname);
|
|
int i = atoi(entryname+8);
|
|
if (SetBit(shapeFlag,i))
|
|
{
|
|
// Error: This was already set
|
|
ReportError(CString(pagename)+":"+CString(notename)+" set multiple times.");
|
|
}
|
|
}
|
|
else if (0==stricmp(notename,"LODDist"))
|
|
{
|
|
listDist.AddTail(entryname);
|
|
int i = atoi(entryname+7);
|
|
if (SetBit(distFlag,i))
|
|
{
|
|
// Error: This was already set
|
|
ReportError(CString(pagename)+":"+CString(notename)+" set multiple times.");
|
|
}
|
|
}
|
|
else if (0==stricmp(notename,"LODChar"))
|
|
{
|
|
listChar.AddTail(entryname);
|
|
int i = atoi(entryname+7);
|
|
if (SetBit(charFlag,i))
|
|
{
|
|
// Error: This was already set
|
|
ReportError(CString(pagename)+":"+CString(notename)+" set multiple times.");
|
|
}
|
|
}
|
|
else if (0==stricmp(notename,"LODDam"))
|
|
{
|
|
listDam.AddTail(entryname);
|
|
int i = atoi(entryname+6);
|
|
if (SetBit(damFlag,i))
|
|
{
|
|
// Error: This was already set
|
|
ReportError(CString(pagename)+":"+CString(notename)+" set multiple times.");
|
|
}
|
|
}
|
|
/************************/
|
|
}
|
|
Check_Object(notes);
|
|
delete notes;
|
|
|
|
/************************/
|
|
// Cross reference data
|
|
|
|
// Check that the LOD distances are sequential
|
|
{
|
|
WORD w = distFlag;
|
|
while (w & 1)
|
|
{
|
|
w = w>>1;
|
|
}
|
|
if (w)
|
|
{
|
|
// Error: LODDist is not sequential
|
|
ReportError(CString(pagename)+": LODDist is not sequential.");
|
|
}
|
|
}
|
|
|
|
// Check that we are doing either a shape or a character
|
|
bool bCharacter = (1 == listChar.GetCount());
|
|
if (listShape.GetCount())
|
|
{
|
|
if (bCharacter)
|
|
{
|
|
// Error: Specified both character and shape
|
|
ReportError(CString(pagename)+": Specified both character and shape.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!bCharacter)
|
|
{
|
|
// Error: Specified neither character or shape
|
|
ReportError(CString(pagename)+": Needs to specify LOD Character or Shape");
|
|
}
|
|
}
|
|
|
|
// Check that if any LOD damage is specified that they match the distances
|
|
if (listDam.GetCount())
|
|
{
|
|
if (damFlag != distFlag)
|
|
{
|
|
// Error: LOD Damage does not match LOD Distances
|
|
ReportError(CString(pagename)+": LODDam does not match LODDist");
|
|
}
|
|
// Check that these files exist
|
|
POSITION pos = listDam.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CString name = listDam.GetNext(pos);
|
|
if (!gos_DoesFileExist(name))
|
|
{
|
|
// Error: File Does not exist
|
|
ReportError(CString(pagename)+": "+name+" Does not exist.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check that if any LOD char is specified that they match the distances
|
|
if (listChar.GetCount())
|
|
{
|
|
if (charFlag != distFlag)
|
|
{
|
|
// Error: LODChar does not match LODDist
|
|
ReportError(CString(pagename)+": LODChar does not match LODDist");
|
|
}
|
|
// LODSkel is required
|
|
if (0 == skel.GetLength())
|
|
{
|
|
// Error: LODSkel is required for Character export
|
|
ReportError(CString(pagename)+": LODSkel is required for character export.");
|
|
}
|
|
|
|
// Note: Anim and OBB are optional for Character export
|
|
// Check that these files exist
|
|
POSITION pos = listChar.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CString name = listChar.GetNext(pos);
|
|
if (!gos_DoesFileExist(name))
|
|
{
|
|
// Error: File Does not exist
|
|
ReportError(CString(pagename)+": "+name+" Does not exist.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check that if any LOD shape is specified that they match the distances
|
|
if (listShape.GetCount())
|
|
{
|
|
if (shapeFlag != distFlag)
|
|
{
|
|
// Error: LODShape does not match LODDist
|
|
ReportError(CString(pagename)+": LODShape does not match LODDist.");
|
|
}
|
|
if (skel.GetLength())
|
|
{
|
|
// Error: LODSkel not needed for shape export
|
|
ReportError(CString(pagename)+": LODSkel not needed for shape export.");
|
|
}
|
|
if (anim.GetLength())
|
|
{
|
|
// Error: anim not needed for shape export
|
|
ReportError(CString(pagename)+": "+anim+" not needed for shape export.");
|
|
}
|
|
|
|
// Note: OBB is optional for Shape export
|
|
|
|
// Check that these files exist
|
|
POSITION pos = listShape.GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
CString name = listShape.GetNext(pos);
|
|
if (!gos_DoesFileExist(name))
|
|
{
|
|
// Error: File Does not exist
|
|
ReportError(CString(pagename)+": "+name+" Does not exist.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (path.GetLength())
|
|
{
|
|
if (!gos_DoesFileExist(path))
|
|
{
|
|
// Error: File Does not exist
|
|
ReportError(CString(pagename)+": "+path+" Does not exist.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Error: Path is required
|
|
ReportError(CString(pagename)+": Path is required.");
|
|
}
|
|
|
|
if (skel.GetLength())
|
|
{
|
|
if (!gos_DoesFileExist(skel))
|
|
{
|
|
// Error: File Does not exist
|
|
ReportError(CString(pagename)+": "+skel+" Does not exist.");
|
|
}
|
|
}
|
|
|
|
if (anim.GetLength())
|
|
{
|
|
if (!gos_DoesFileExist(anim))
|
|
{
|
|
// Error: File Does not exist
|
|
ReportError(CString(pagename)+": "+anim+" Does not exist.");
|
|
}
|
|
}
|
|
|
|
if (obb.GetLength())
|
|
{
|
|
if (!gos_DoesFileExist(obb))
|
|
{
|
|
// Error: File Does not exist
|
|
ReportError(CString(pagename)+": "+obb+" Does not exist.");
|
|
}
|
|
}
|
|
|
|
int err;
|
|
if (skel.GetLength())
|
|
err = m_ip->LoadFromFile(skel);
|
|
|
|
// Load the skeleton and save the names of the geometry nodes (mesh nodes)
|
|
/*CStringList meshList;
|
|
int count = FindGeometry(&meshList,m_ip->GetRootNode());
|
|
*/
|
|
// Verify that all Geometry node names in LOD are in skeleton
|
|
|
|
// Check that the OBB file has collision volumes - run skeleton verify too?
|
|
// This is the CV exporter code:
|
|
|
|
static int runcv = 0;
|
|
if (runcv)
|
|
{
|
|
MaxCollisionVolume *pCv = NULL;
|
|
|
|
CString name_world("joint_WORLD");
|
|
INode *pRoot = FindNodeByName(m_ip->GetRootNode(),name_world);
|
|
if (pRoot != NULL)
|
|
{
|
|
pCv = ConstructCVHeirarchy(pRoot);
|
|
Check_Object(pCv);
|
|
}
|
|
else
|
|
{
|
|
// this is not a heiracrhied object so recurse the first level children looking for
|
|
// cv's.
|
|
int cv_children = 0;
|
|
for (int x=0;x<m_ip->GetRootNode()->NumberOfChildren();x++)
|
|
{
|
|
INode *pChild = m_ip->GetRootNode()->GetChildNode(x);
|
|
|
|
if (!strnicmp(pChild->GetName(),"cv_",3))
|
|
{
|
|
MaxCollisionVolume *child_cv = ConstructCVHeirarchy(pChild);
|
|
|
|
if (child_cv != NULL)
|
|
{
|
|
// make sure we haven't found more than one base child that is a cv.
|
|
Check_Object(child_cv);
|
|
++cv_children;
|
|
if (cv_children > 1)
|
|
{
|
|
// Error: Objects are only allowed to have one base cv...
|
|
CString str = CString(pChild->GetName())+"Objects are only allowed to have one base cv . All other CV's must be childed off of that base parent";
|
|
ReportError(str);
|
|
//STOP(("Objects are only allowed to have one base cv . All other CV's must be childed off of that base parent"));
|
|
}
|
|
|
|
pCv = child_cv;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
if (pCv)
|
|
{
|
|
if (pRoot != NULL)
|
|
{
|
|
// pVel is now the root of the heiarchy so far, let's export the SOLID obb
|
|
|
|
{
|
|
// find the velocity colision volume
|
|
MaxCollisionVolume* cv_velocity = pCv->FindCVNode("joint_WORLD");
|
|
if (NULL == cv_velocity)
|
|
{
|
|
// Error: ...
|
|
// NEED to report the error
|
|
//STOP(("Exporting OBB of a mech with no collision volumes. TODO: report this error and continue for batch export."));
|
|
//CString str = "Error exporting OBB: "+CString(name)+" has no collision volume under joint_WORLD";
|
|
//AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
//AfxMessageBox(str, MB_OK);
|
|
delete pCv;
|
|
return false;
|
|
}
|
|
Check_Object(cv_velocity);
|
|
//deleteing velocity automaticly removes it from the heirarchy.
|
|
// this is a behavior of chain.
|
|
delete cv_velocity;
|
|
Unregister_Pointer(cv_velocity);
|
|
}
|
|
}
|
|
delete pCv;
|
|
}
|
|
else
|
|
{
|
|
CString str = CString(skel)+" does not contain any collision volumes.";
|
|
ReportError(str);
|
|
}
|
|
}
|
|
|
|
/************************/
|
|
}
|
|
delete pages;
|
|
return 1;
|
|
}
|
|
|