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.
393 lines
10 KiB
C++
393 lines
10 KiB
C++
/***************************************************************************
|
|
* *
|
|
* 3DS Max Test Plugin *
|
|
* *
|
|
***************************************************************************
|
|
* *
|
|
* Version : 1.0ß, March 11th, 1998 *
|
|
* *
|
|
* Written By Loic Baumann from Fatal Design, specially for Gamasutra *
|
|
* *
|
|
***************************************************************************
|
|
* *
|
|
* This Plugin demonstrates how to write a simple 3DS MAX Plugin, using MFCs *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#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 <DLLPlatform\DLLPlatform.hpp>
|
|
|
|
#include "MissionImp.h"
|
|
#include "ExportUtil.h"
|
|
|
|
//#ifdef _DEBUG
|
|
//#define new DEBUG_NEW
|
|
//#undef THIS_FILE
|
|
//static char THIS_FILE[] = __FILE__;
|
|
//#endif
|
|
|
|
#include <direct.h>
|
|
#include "ExportUtil.h"
|
|
//#include "mapsizedlg.h"
|
|
|
|
//===========================================================================//
|
|
int MissionImp::DoImport(const TCHAR *name, ImpInterface *ii,Interface *i, BOOL suppressPrompts)
|
|
{
|
|
int return_value;
|
|
__try
|
|
{
|
|
m_ip = i;
|
|
m_suppress = suppressPrompts?true:false;
|
|
return_value = ImportMission(name);
|
|
//return_value = true;
|
|
GetSystemSetting(SYSSET_CLEAR_UNDO);
|
|
Verify(!theHold.Holding());
|
|
}
|
|
__except(ProcessException(GetExceptionInformation()))
|
|
{
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
// in maxpolygonmesh.cpp
|
|
Quat ConvertMWToMax(UnitQuaternion &quat);
|
|
Point3 ConvertMWToMax(Stuff::Point3D &pnt);
|
|
|
|
/*******************************************************************************
|
|
/* function name: ImportVideo
|
|
/* description: Import .video files
|
|
/*******************************************************************************/
|
|
int MissionImp::ImportVideo(const char *name,Quat maxrot,Point3 maxtrans)
|
|
{
|
|
CString filename = GetGamePath(m_ip) + "content\\"+name;
|
|
NotationFile videofile(filename);
|
|
Page *page = videofile.FindPage("LOD");
|
|
if (page)
|
|
{
|
|
const char *entry;
|
|
if (page->GetEntry("Geometry",&entry))
|
|
{
|
|
char path[MAX_PATH];
|
|
_splitpath(name,NULL,path,NULL,NULL);
|
|
|
|
CString path1(path);
|
|
// trim "armaturevideo from the tail of the path
|
|
path1.MakeLower();
|
|
int index = path1.Find("armaturevideo");
|
|
if (index>0)
|
|
{
|
|
path1 = path1.Left(index);
|
|
}
|
|
|
|
CString erfpath = GetGamePath(m_ip) + "content\\";
|
|
erfpath+=path1;
|
|
erfpath+=entry;
|
|
|
|
if (m_ip->ImportFromFile(erfpath,false))
|
|
{
|
|
// Move any node with name not starting with "_" to the rotation/translation coordinates
|
|
Matrix3 axis(MAT_IDENT);
|
|
INode *pWorld = m_ip->GetRootNode();
|
|
for (int x=0;x<pWorld->NumberOfChildren();x++)
|
|
{
|
|
INode *pChild = pWorld->GetChildNode(x);
|
|
CString name = pChild->GetName();
|
|
if (strnicmp(name,"_",1))
|
|
{
|
|
name = CString("_")+name;//name;
|
|
pChild->SetName((char *)(LPCTSTR)name);
|
|
pChild->Rotate(0,axis,maxrot);
|
|
pChild->Move(0,axis,maxtrans);
|
|
|
|
Quat fixrot(0.0,0.0,PI/2.0,0.0);
|
|
// Now move and rotate to the terrain's coordinate system
|
|
// pChild->Move(0,axis,fixtrans);
|
|
pChild->Rotate(0,axis,fixrot);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
/* function name: ImportModel
|
|
/* description: Import .data files
|
|
/*******************************************************************************/
|
|
int MissionImp::ImportModel(const char *name,Quat maxrot,Point3 maxtrans)
|
|
{
|
|
CString filename = GetGamePath(m_ip) + "content\\"+name;
|
|
NotationFile modelfile(filename);
|
|
Page *page = modelfile.FindPage("Renderers");
|
|
if (page)
|
|
{
|
|
const char *entry;
|
|
if (page->GetEntry("VideoRenderer",&entry))
|
|
{
|
|
char path[MAX_PATH];
|
|
_splitpath(name,NULL,path,NULL,NULL);
|
|
CString filename(path);
|
|
// trim "armaturedata from the tail of the path
|
|
filename.MakeLower();
|
|
int index = filename.Find("armaturedata");
|
|
if (index>0)
|
|
{
|
|
filename = filename.Left(index);
|
|
}
|
|
filename+=entry;
|
|
return ImportVideo(filename,maxrot,maxtrans);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct ARMNODE
|
|
{
|
|
ARMNODE *parent;
|
|
CString name;
|
|
const char *model;
|
|
Quat rot;
|
|
Point3 trans;
|
|
};
|
|
|
|
/*******************************************************************************
|
|
/* function name: ImportArmature
|
|
/* description: Import .armature files
|
|
/*******************************************************************************/
|
|
int MissionImp::ImportArmature(const char *name,Quat maxrot,Point3 maxtrans)
|
|
{
|
|
CString filename = GetGamePath(m_ip) + "content\\"+name;
|
|
NotationFile armfile(filename);
|
|
NotationFile::PageIterator *pages = armfile.MakePageIterator();
|
|
|
|
CMapStringToPtr mapNode;
|
|
|
|
ARMNODE *pRoot = NULL;
|
|
Page *page;
|
|
while (page = pages->ReadAndNext())
|
|
{
|
|
ARMNODE *pNode = new ARMNODE;
|
|
if (NULL == pRoot)
|
|
pRoot = pNode;
|
|
|
|
pNode->name = page->GetName();
|
|
pNode->name.MakeLower();
|
|
mapNode[pNode->name] = pNode;
|
|
pNode->parent = NULL;
|
|
pNode->rot.Identity();
|
|
pNode->trans = Point3(0,0,0);
|
|
pNode->model = NULL;
|
|
}
|
|
delete pages;
|
|
|
|
pages = armfile.MakePageIterator();
|
|
while (page = pages->ReadAndNext())
|
|
{
|
|
CString name = page->GetName();
|
|
name.MakeLower();
|
|
|
|
ARMNODE *pNode = (ARMNODE *)mapNode[name];
|
|
Page::NoteIterator *notes = page->MakeNoteIterator();
|
|
Note *note;
|
|
while (note = notes->ReadAndNext())
|
|
{
|
|
if (0==stricmp(note->GetName(),"rotation"))
|
|
{
|
|
YawPitchRoll ypr;
|
|
note->GetEntry(&ypr);
|
|
{
|
|
UnitQuaternion rotation;
|
|
rotation = ypr;
|
|
pNode->rot = ConvertMWToMax(rotation);
|
|
}
|
|
}
|
|
|
|
if (0==stricmp(note->GetName(),"translation"))
|
|
{
|
|
Point3D translation;
|
|
note->GetEntry(&translation);
|
|
{
|
|
pNode->trans = ConvertMWToMax(translation);
|
|
}
|
|
}
|
|
|
|
if (0==stricmp(note->GetName(),"child"))
|
|
{
|
|
const char *child;
|
|
note->GetEntry(&child);
|
|
{
|
|
CString str(child);
|
|
str.MakeLower();
|
|
|
|
ARMNODE *pChild = (ARMNODE *)mapNode[str];
|
|
Check_Pointer(pChild);
|
|
pChild->parent = pNode;
|
|
if (pChild == pRoot)
|
|
pRoot= pNode;
|
|
}
|
|
}
|
|
|
|
if (0==stricmp(note->GetName(),"model"))
|
|
{
|
|
const char *model;
|
|
note->GetEntry(&model);
|
|
{
|
|
pNode->model = model;
|
|
}
|
|
}
|
|
}
|
|
delete notes;
|
|
}
|
|
delete pages;
|
|
|
|
int count = 0;
|
|
POSITION pos = mapNode.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
CString key;
|
|
LPVOID value;
|
|
mapNode.GetNextAssoc(pos,key,value);
|
|
ARMNODE *pNode = (ARMNODE *)value;
|
|
if (pNode->model)
|
|
{
|
|
Quat q = pNode->rot;
|
|
Point3 p = pNode->trans;
|
|
|
|
ARMNODE *pParent = pNode->parent;
|
|
while (pParent)
|
|
{
|
|
q+=pParent->rot;
|
|
p+=pParent->trans;
|
|
pParent = pParent->parent;
|
|
}
|
|
|
|
q+=maxrot;
|
|
p+=maxtrans;
|
|
|
|
char path[MAX_PATH];
|
|
_splitpath(name,NULL,path,NULL,NULL);
|
|
CString filename(path);
|
|
filename+=pNode->model;
|
|
count += ImportModel(filename,q,p);
|
|
}
|
|
}
|
|
|
|
pos = mapNode.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
CString key;
|
|
LPVOID value;
|
|
mapNode.GetNextAssoc(pos,key,value);
|
|
ARMNODE *pNode = (ARMNODE *)value;
|
|
delete pNode;
|
|
}
|
|
mapNode.RemoveAll();
|
|
return count;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
/* function name: ImportPage
|
|
/* description: Import an object from a mission contents file
|
|
/*******************************************************************************/
|
|
int MissionImp::ImportPage(Page *page)
|
|
{
|
|
Quat maxrot;
|
|
Point3 maxtrans;
|
|
maxrot.Identity();
|
|
maxtrans = Point3(0,0,0);
|
|
|
|
YawPitchRoll ypl;
|
|
if (page->GetEntry("rotation",&ypl))
|
|
{
|
|
UnitQuaternion rotation;
|
|
rotation = ypl;
|
|
maxrot = ConvertMWToMax(rotation);
|
|
}
|
|
|
|
Point3D translation;
|
|
if (page->GetEntry("translation",&translation))
|
|
{
|
|
maxtrans = ConvertMWToMax(translation);
|
|
}
|
|
|
|
// Now import the buildings only
|
|
const char *entry;
|
|
if (page->GetEntry("armature",&entry))
|
|
{
|
|
if (0==strnicmp(entry,"buildings",9))
|
|
return ImportArmature(entry,maxrot,maxtrans);
|
|
}
|
|
|
|
if (page->GetEntry("model",&entry))
|
|
{
|
|
if (0==strnicmp(entry,"buildings",9))
|
|
return ImportModel(entry,maxrot,maxtrans);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
/* function name: ImportMission
|
|
/* description: Import a mission .contents file
|
|
/*******************************************************************************/
|
|
int MissionImp::ImportMission(const CString& fileName)
|
|
{
|
|
Point3 fixtrans;
|
|
fixtrans.x = 0;
|
|
fixtrans.y = 0;
|
|
Quat fixrot(0.0,0.0,PI/2.0,0.0);
|
|
|
|
INode *pWorld = m_ip->GetRootNode();
|
|
for (int x=0;x<pWorld->NumberOfChildren();x++)
|
|
{
|
|
INode *pChild = pWorld->GetChildNode(x);
|
|
CString name = pChild->GetName();
|
|
if (strnicmp(name,"_",1))
|
|
{
|
|
name = CString("_")+name;//name;
|
|
pChild->SetName((char *)(LPCTSTR)name);
|
|
}
|
|
}
|
|
|
|
// Change directory to game path
|
|
CString gamepath = GetGamePath(m_ip);
|
|
char tpath[MAX_PATH];
|
|
getcwd(tpath,MAX_PATH);
|
|
chdir(gamepath);
|
|
NotationFile notefile(fileName);
|
|
|
|
m_ip->ProgressStart((char *)(LPCTSTR)(CString("Importing ")+fileName),false,fn,NULL);
|
|
|
|
Page *page;
|
|
NotationFile::PageIterator *pages = notefile.MakePageIterator();
|
|
Check_Object(pages);
|
|
|
|
int count = 0;
|
|
int progress = 0;
|
|
int maxcount = pages->GetSize();
|
|
while (page = pages->ReadAndNext())
|
|
{
|
|
progress++;
|
|
m_ip->ProgressUpdate((int)(((float)progress/(float)maxcount)*100.0f),false,(char *)page->GetName());
|
|
count += ImportPage(page);
|
|
}
|
|
m_ip->ProgressEnd();
|
|
delete pages;
|
|
|
|
chdir(tpath);
|
|
return true;
|
|
}
|
|
|