681 lines
15 KiB
C++
681 lines
15 KiB
C++
/**********************************************************************
|
|
DESCRIPTION: .MOD file export
|
|
CREATED BY: Boujemaa
|
|
**********************************************************************/
|
|
|
|
#include "StdAfx.h"
|
|
#include "resource.h"
|
|
#include "ModExp.h"
|
|
#include "modobject.h"
|
|
|
|
|
|
HINSTANCE hInstance;
|
|
int controlsInit = FALSE;
|
|
|
|
CModExport* g_Eporter = NULL;
|
|
|
|
TCHAR* GetString(int id)
|
|
{
|
|
static TCHAR stBuf[ERROR_MSG_MAX_LEN];
|
|
if (hInstance)
|
|
return LoadString(hInstance, id, stBuf, ERROR_MSG_MAX_LEN) ? stBuf : NULL;
|
|
return NULL;
|
|
}
|
|
|
|
static int Alert(int s1, int s2 = IDS_MODEXP, int option = MB_OK) {
|
|
return MessageBox(g_Eporter->m_Gi->GetMAXHWnd(), GetString(s1), GetString(s2), option);
|
|
}
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) {
|
|
|
|
// Hang on to this DLL's instance handle.
|
|
hInstance = hinstDLL;
|
|
|
|
if ( !controlsInit ) {
|
|
controlsInit = TRUE;
|
|
|
|
// Initialize 3ds Max's custom controls
|
|
InitCustomControls(hInstance);
|
|
|
|
// Initialize Windows controls
|
|
InitCommonControls();
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static CModExpClassDesc _ModExpDesc;
|
|
|
|
__declspec( dllexport ) const TCHAR * LibDescription() {
|
|
return GetString(IDS_MODEXPDLL);
|
|
}
|
|
|
|
__declspec( dllexport ) int
|
|
LibNumberClasses()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
__declspec( dllexport ) ClassDesc *
|
|
LibClassDesc(int i)
|
|
{
|
|
switch(i) {
|
|
case 0: return &_ModExpDesc; break;
|
|
default: return 0; break;
|
|
}
|
|
}
|
|
|
|
// Return version so can detect obsolete DLLs
|
|
__declspec( dllexport ) ULONG LibVersion()
|
|
{
|
|
return VERSION_3DSMAX;
|
|
}
|
|
|
|
inline const TCHAR* CModExpClassDesc::Category()
|
|
{
|
|
return GetString(IDS_SCENEEXPORT);
|
|
}
|
|
|
|
inline SClass_ID CModExpClassDesc::SuperClassID()
|
|
{
|
|
return SCENE_EXPORT_CLASS_ID;
|
|
}
|
|
|
|
inline Class_ID CModExpClassDesc::ClassID()
|
|
{
|
|
return Class_ID(0x7d285801, 0x3c7b4aaa);
|
|
}
|
|
|
|
inline const TCHAR * CModExpClassDesc::ClassName()
|
|
{
|
|
return GetString(IDS_UBIMOD);
|
|
}
|
|
|
|
inline int CModExpClassDesc::IsPublic()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
inline void * CModExpClassDesc::Create(BOOL loading)
|
|
{
|
|
g_Eporter = new CModExport;
|
|
return g_Eporter;
|
|
|
|
}
|
|
|
|
CModExport::CModExport()
|
|
{
|
|
m_exportSelected = 0;
|
|
m_showPrompts = 1;
|
|
m_Gi = NULL;
|
|
m_ei = NULL;
|
|
}
|
|
|
|
CModExport::~CModExport()
|
|
{
|
|
}
|
|
|
|
int CModExport::GetExportOptions(DWORD _options, BOOL _suppressPrompts)
|
|
{
|
|
m_showPrompts = _suppressPrompts ? FALSE : TRUE;
|
|
m_exportSelected = (_options & SCENE_EXPORT_SELECTED) ? TRUE : FALSE;
|
|
return 1;
|
|
}
|
|
|
|
int CModExport::DumpHeader(WorkFile &modFile, BOOL _isSpo)
|
|
{
|
|
char currentCmd[MAX_MOD_COMMAND_LEN];
|
|
|
|
{
|
|
modFile.OutLine("; (c) Ubi Casablanca");
|
|
}
|
|
{
|
|
char filename[MAX_FILE_NAME];
|
|
|
|
_splitpath(modFile.GetFileName(), NULL, NULL, filename, NULL);
|
|
|
|
if (_isSpo)
|
|
{
|
|
strcat(filename, ".SPO");
|
|
sprintf(currentCmd, ";.SPO (graphic Module) : %s", filename);
|
|
}
|
|
else
|
|
{
|
|
strcat(filename, ".MOD");
|
|
sprintf(currentCmd, ";.MOD (graphic Module) : %s", filename);
|
|
}
|
|
|
|
modFile.SetShortfName(filename);
|
|
|
|
modFile.OutLine(currentCmd);
|
|
}
|
|
|
|
{
|
|
assert(m_Gi != NULL);
|
|
sprintf(currentCmd, ";Generated from file %s", m_Gi->GetCurFileName());
|
|
modFile.OutLine(currentCmd);
|
|
}
|
|
|
|
{
|
|
struct tm *newtime;
|
|
time_t aclock;
|
|
time( &aclock ); // Get time in seconds
|
|
newtime = localtime( &aclock ); // Convert time to struct tm form
|
|
/* Print local time as a string */
|
|
sprintf( currentCmd, ";Creation date : %s", asctime( newtime ) );
|
|
modFile.OutLine(currentCmd);
|
|
}
|
|
|
|
/*
|
|
;Version directive, the version number is stored in file result 0
|
|
$SetCurrentFileDouble(0,"5.20")
|
|
|
|
;Unit directive, the unit is stored in file result 1
|
|
;And correspond to the value of one unit exprimed in meter
|
|
$SetCurrentFileDouble(1,1)
|
|
*/
|
|
modFile.OutLine(";Version directive, the version number is stored in file result 0");
|
|
modFile.OutLine("$SetCurrentFileDouble(0,\"5.20\")\n");
|
|
modFile.OutLine(";Unit directive, the unit is stored in file result 1");
|
|
modFile.OutLine(";And correspond to the value of one unit exprimed in meter");
|
|
modFile.OutLine("$SetCurrentFileDouble(1,1)\n");
|
|
|
|
return 1;
|
|
}
|
|
int CModExport::DumpData(WorkFile &_modFile,WorkFile &_spoFile)
|
|
{
|
|
|
|
// Make sure there are nodes we're interested in!
|
|
// Ask the scene to enumerate all its nodes so we can determine if there are any we can use
|
|
SceneEnumProc myScene(g_Eporter->m_Gi->GetTime());
|
|
m_ei->theScene->EnumTree(&myScene);
|
|
|
|
// Any useful nodes?
|
|
if(myScene.Count() == 0)
|
|
{
|
|
if(m_showPrompts)
|
|
Alert(IDS_NODATATOEXPORT);
|
|
return 1;
|
|
}
|
|
|
|
myScene.DumpGeoms(_modFile);
|
|
myScene.DumpMtls(_modFile);
|
|
|
|
myScene.DumpRoot(_spoFile);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CModExport::ExportFile(const TCHAR *_filename)
|
|
{
|
|
|
|
TSTR LvlName;
|
|
TSTR LvlPath;
|
|
SplitFilename((TSTR)_filename, &LvlPath, &LvlName, NULL);
|
|
strcat(LvlPath, "\\");
|
|
strcat(LvlPath, LvlName);
|
|
strcat(LvlPath, ".SPO");
|
|
|
|
WorkFile modFile(_filename,"wt");
|
|
WorkFile spoFile(LvlPath,"wt");
|
|
|
|
DumpHeader(modFile);
|
|
DumpHeader(spoFile, true);
|
|
DumpData(modFile,spoFile);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CModExport::DoExport(const TCHAR *filename,ExpInterface *ei,Interface *gi, BOOL suppressPrompts, DWORD options)
|
|
{
|
|
|
|
int result;
|
|
m_Gi = gi;
|
|
m_ei = ei;
|
|
result = GetExportOptions(options, suppressPrompts);
|
|
if (!result)
|
|
return 0;
|
|
result = ExportFile(filename);
|
|
|
|
return result;
|
|
}
|
|
|
|
void CModExport::ShowAbout(HWND hWnd)
|
|
{
|
|
// Optional
|
|
}
|
|
unsigned int CModExport::Version()
|
|
{
|
|
// Version number * 100 (i.e. v3.01 = 301)
|
|
return 100;
|
|
}
|
|
|
|
int CModExport::ExtCount()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
const TCHAR * CModExport::Ext(int n)
|
|
{ // Extensions supported for import/export modules
|
|
switch(n) {
|
|
case 0:
|
|
return _T("MOD");
|
|
}
|
|
return _T("");
|
|
}
|
|
|
|
const TCHAR * CModExport::LongDesc()
|
|
{ // Long ASCII description (i.e. "Targa 2.0 Image File")
|
|
return GetString(IDS_MODSCENEFILE);
|
|
}
|
|
|
|
const TCHAR * CModExport::ShortDesc()
|
|
{ // Short ASCII description (i.e. "Targa")
|
|
return GetString(IDS_MODFILE);
|
|
}
|
|
|
|
const TCHAR * CModExport::AuthorName()
|
|
{ // ASCII Author name
|
|
return GetString(IDS_UBICASA);
|
|
}
|
|
|
|
const TCHAR * CModExport::OtherMessage1()
|
|
{ // Other message #1
|
|
return _T("");
|
|
}
|
|
|
|
const TCHAR * CModExport::OtherMessage2()
|
|
{ // Other message #2
|
|
return _T("");
|
|
}
|
|
const TCHAR * CModExport::CopyrightMessage()
|
|
{ // ASCII Copyright message
|
|
return GetString(IDS_COPYRIGHT_UBI);
|
|
}
|
|
|
|
void WorkFile::OutLine(char* _txtLine)
|
|
{
|
|
fprintf(stream, "%s\n", _txtLine);
|
|
}
|
|
|
|
SceneEnumProc::SceneEnumProc(TimeValue time)
|
|
{
|
|
m_time = time;
|
|
m_count = 0;
|
|
m_root = new CSuperObject(NULL);
|
|
}
|
|
SceneEnumProc::~SceneEnumProc()
|
|
{
|
|
m_GeomList.clear();
|
|
m_MatList.clear();
|
|
delete m_root;
|
|
}
|
|
|
|
int SceneEnumProc::callback(INode *node)
|
|
{
|
|
|
|
if(g_Eporter->m_exportSelected && node->Selected() == FALSE)
|
|
return TREE_CONTINUE;
|
|
|
|
Append(node);
|
|
|
|
return TREE_CONTINUE;
|
|
}
|
|
|
|
void SceneEnumProc::Append(INode *_node)
|
|
{
|
|
|
|
if (_node->IsRootNode())
|
|
return;
|
|
|
|
// find parent
|
|
INode * Parentnode = _node->GetParentNode();
|
|
|
|
CSuperObject *ParentSpo;
|
|
|
|
if (Parentnode->IsRootNode())
|
|
ParentSpo = m_root;
|
|
else
|
|
ParentSpo = m_root->findSpo(Parentnode);
|
|
|
|
if (ParentSpo == NULL)
|
|
{
|
|
ParentSpo = m_root;
|
|
}
|
|
|
|
if (ParentSpo == m_root)
|
|
{
|
|
|
|
char NodeName[MAX_NAME_OBJ];
|
|
strcpy(NodeName,_node->GetName());
|
|
strlwr(NodeName);
|
|
if ((NodeName[0] != 's') ||
|
|
(NodeName[1] != 'c') ||
|
|
(NodeName[2] != 't'))
|
|
{
|
|
// object not linked to any dumy
|
|
assert(0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// create sop
|
|
CSuperObject *NewSpo = new CSuperObject(_node);
|
|
|
|
ParentSpo->AddNode(NewSpo);
|
|
|
|
Object *obj = _node->EvalWorldState(m_time).obj;
|
|
if (obj->CanConvertToType(triObjectClassID))
|
|
{
|
|
m_GeomList.push_back(NewSpo);
|
|
m_count ++;
|
|
}
|
|
|
|
}
|
|
void SceneEnumProc::AppendMat(Mtl *_mtl)
|
|
{
|
|
std::list <Mtl *>::iterator Iter;
|
|
for ( Iter = m_MatList.begin( ); Iter != m_MatList.end( ); Iter++ )
|
|
{
|
|
Mtl *current = *Iter;
|
|
if (current == _mtl)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
m_MatList.push_back(_mtl);
|
|
}
|
|
|
|
void SceneEnumProc::DumpGeoms(WorkFile &modFile)
|
|
{
|
|
std::list <CSuperObject *>::iterator Iter;
|
|
for ( Iter = m_GeomList.begin( ); Iter != m_GeomList.end( ); Iter++ )
|
|
{
|
|
DumpOneGeom(modFile, *Iter);
|
|
}
|
|
}
|
|
|
|
void SceneEnumProc::DumpRoot(WorkFile &_spoFile)
|
|
{
|
|
m_root->DumpSpo(_spoFile, m_time);
|
|
}
|
|
|
|
void SceneEnumProc::DumpMtls(WorkFile &modFile)
|
|
{
|
|
std::list <Mtl*>::iterator Iter;
|
|
for ( Iter = m_MatList.begin( ); Iter != m_MatList.end( ); Iter++ )
|
|
{
|
|
DumpOneMtl(modFile, *Iter);
|
|
}
|
|
}
|
|
|
|
void SceneEnumProc::DumpOneGeom(WorkFile &modFile, CSuperObject *_node)
|
|
{
|
|
char currentCmd[MAX_MOD_COMMAND_LEN];
|
|
int i = 0;
|
|
std::vector <CModElem*>::iterator IterElem;
|
|
std::vector <CFace>::iterator IterFace;
|
|
std::vector <CUV>::iterator IterUV;
|
|
|
|
CModObject curObj(_node->m_maxNode, m_time);
|
|
|
|
if (!curObj.m_ValidObj)
|
|
return;
|
|
|
|
int nbrElems = 0;
|
|
for ( IterElem = curObj.m_elements.begin( ); IterElem != curObj.m_elements.end( ); IterElem++ )
|
|
{
|
|
CModElem* elem = *IterElem;
|
|
if (elem->m_Faces.size() != 0)
|
|
{
|
|
SceneEnumProc::AppendMat(elem->m_material);
|
|
nbrElems++;
|
|
}
|
|
}
|
|
|
|
|
|
// set spo link
|
|
sprintf(currentCmd, "Geometric(\"%s^Geometric:%s\")", modFile.GetShortfName(), curObj.m_name);
|
|
_node->SetGeomLink(currentCmd);
|
|
// geom
|
|
sprintf(currentCmd, "{Geometric:%s(%d,0,%d)", curObj.m_name, curObj.m_nbrVrtx, nbrElems);
|
|
modFile.OutLine(currentCmd);
|
|
|
|
// vertxs
|
|
|
|
for (i = 0; i < curObj.m_Vertxs.size(); i++)
|
|
{
|
|
sprintf(currentCmd, "\tAddVertex(%d,\"%g\",\"%g\",\"%g\",\"%g\",\"%g\",\"%g\",0,0,0)",
|
|
i,
|
|
curObj.m_Vertxs[i].x, curObj.m_Vertxs[i].y, curObj.m_Vertxs[i].z,
|
|
curObj.m_Vertxs[i].nx, curObj.m_Vertxs[i].ny, curObj.m_Vertxs[i].nz);
|
|
modFile.OutLine(currentCmd);
|
|
}
|
|
|
|
// Geomelem
|
|
|
|
i=0;
|
|
for ( IterElem = curObj.m_elements.begin( ); IterElem != curObj.m_elements.end( ); IterElem++ )
|
|
{
|
|
CModElem* elem = *IterElem;
|
|
if (elem->m_Faces.size() != 0)
|
|
{
|
|
sprintf(currentCmd, "\tAddElement(%d,IndexedTriangles,\"*^ElementIndexedTriangles:%s_%s\")",i, curObj.m_name, elem->m_name);
|
|
modFile.OutLine(currentCmd);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
modFile.OutLine("}");
|
|
|
|
// elems
|
|
for ( IterElem = curObj.m_elements.begin( ); IterElem != curObj.m_elements.end( ); IterElem++ )
|
|
{
|
|
CModElem* elem = *IterElem;
|
|
if (elem->m_Faces.size() != 0)
|
|
{
|
|
sprintf(currentCmd, "{ElementIndexedTriangles:%s_%s(%d,%d)", curObj.m_name, elem->m_name,elem->m_Faces.size(),elem->m_UVs.size());
|
|
modFile.OutLine(currentCmd);
|
|
sprintf(currentCmd, "\tMaterial(\"*^Material:%s\")", elem->m_name);
|
|
modFile.OutLine(currentCmd);
|
|
i = 0;
|
|
for (IterFace = elem->m_Faces.begin(); IterFace != elem->m_Faces.end(); IterFace++)
|
|
{
|
|
CFace* face =&(*IterFace);
|
|
sprintf(currentCmd, "\tAddFaceUV(%d,%d,%d,%d,\"%g\",\"%g\",\"%g\",%d,%d,%d)",
|
|
i,
|
|
face->I, face->J,face->K,
|
|
face->nx, face->ny,face->nz,
|
|
face->IUV, face->JUV,face->KUV);
|
|
modFile.OutLine(currentCmd);
|
|
i++;
|
|
}
|
|
i = 0;
|
|
for (IterUV = elem->m_UVs.begin(); IterUV != elem->m_UVs.end(); IterUV++)
|
|
{
|
|
CUV* uv =&(*IterUV);
|
|
sprintf(currentCmd, "\tAddUV(%d,\"%g\",\"%g\")", i, uv->U, uv->V);
|
|
modFile.OutLine(currentCmd);
|
|
i++;
|
|
}
|
|
modFile.OutLine("}");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void SceneEnumProc::DumpOneMtl(WorkFile &modFile, Mtl *_mtl)
|
|
{
|
|
char currentCmd[MAX_MOD_COMMAND_LEN];
|
|
|
|
sprintf(currentCmd, "{Material:%s", _mtl->GetName());
|
|
modFile.OutLine(currentCmd);
|
|
|
|
sprintf(currentCmd, "\tType(Gouraud)");
|
|
modFile.OutLine(currentCmd);
|
|
|
|
sprintf(currentCmd, "\tAmbientColor(\"%g\",\"%g\",\"%g\")", _mtl->GetAmbient().r, _mtl->GetAmbient().g, _mtl->GetAmbient().b);
|
|
modFile.OutLine(currentCmd);
|
|
|
|
sprintf(currentCmd, "\tDiffuseColor(\"%g\",\"%g\",\"%g\")", _mtl->GetDiffuse().r, _mtl->GetDiffuse().g, _mtl->GetDiffuse().b);
|
|
modFile.OutLine(currentCmd);
|
|
|
|
sprintf(currentCmd, "\tSpecularColor(\"%g\",\"%g\",\"%g\",\"%g\")", _mtl->GetSpecular().r, _mtl->GetSpecular().g, _mtl->GetSpecular().b, _mtl->GetShinStr());
|
|
modFile.OutLine(currentCmd);
|
|
|
|
{
|
|
BitmapTex *tx = (BitmapTex*)_mtl->GetSubTexmap(ID_DI);//ID_DI : diffuse
|
|
char filename[MAX_FILE_NAME];
|
|
char ext[5];
|
|
_splitpath((char*)(tx->GetMapName()), NULL, NULL, filename, ext);
|
|
sprintf(currentCmd, "\tTexture(\"%s%s\")",filename, ext);
|
|
modFile.OutLine(currentCmd);
|
|
}
|
|
{
|
|
if (((StdMat *)_mtl)->GetTwoSided())
|
|
sprintf(currentCmd, "\tBackface(OFF)");
|
|
else
|
|
sprintf(currentCmd, "\tBackface(ON)");
|
|
modFile.OutLine(currentCmd);
|
|
}
|
|
|
|
modFile.OutLine("}");
|
|
|
|
}
|
|
void CSuperObject::AddNode(CSuperObject *_node)
|
|
{
|
|
m_childs.push_back(_node);
|
|
_node->m_Parent = this;
|
|
}
|
|
CSuperObject::CSuperObject(INode *_node)
|
|
{
|
|
if (_node != NULL)
|
|
{
|
|
sprintf(m_name, "SPO_%s", _node->GetName());
|
|
}
|
|
else
|
|
strcpy(m_name, "Root");
|
|
m_maxNode = _node;
|
|
m_GeomLink = NULL;
|
|
m_Parent = NULL;
|
|
}
|
|
CSuperObject::~CSuperObject()
|
|
{
|
|
std::list <CSuperObject*>::iterator Iter;
|
|
for ( Iter = m_childs.begin( ); Iter != m_childs.end( ); Iter++ )
|
|
{
|
|
CSuperObject *spo = *Iter;
|
|
delete spo;
|
|
}
|
|
m_childs.clear();
|
|
if (m_GeomLink)
|
|
delete m_GeomLink;
|
|
}
|
|
void CSuperObject::SetGeomLink(char* _GeomLink)
|
|
{
|
|
if (m_GeomLink == NULL)
|
|
m_GeomLink = new char[MAX_MOD_COMMAND_LEN];
|
|
|
|
strcpy(m_GeomLink, _GeomLink);
|
|
}
|
|
|
|
char* CSuperObject::GetGeomLink()
|
|
{
|
|
return m_GeomLink;
|
|
}
|
|
|
|
CSuperObject* CSuperObject::findSpo(INode *_node)
|
|
{
|
|
if (m_maxNode == _node)
|
|
return this;
|
|
else
|
|
{
|
|
std::list <CSuperObject*>::iterator Iter;
|
|
for ( Iter = m_childs.begin( ); Iter != m_childs.end( ); Iter++ )
|
|
{
|
|
CSuperObject *spo = *Iter;
|
|
CSuperObject *retSpo = spo->findSpo(_node);
|
|
if (retSpo != NULL)
|
|
return retSpo;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CSuperObject::DumpSpo(WorkFile &_spoFile, TimeValue _time)
|
|
{
|
|
char currentCmd[MAX_MOD_COMMAND_LEN];
|
|
std::list <CSuperObject*>::iterator Iter;
|
|
|
|
// dump obj
|
|
|
|
sprintf(currentCmd, "{SuperObject:%s", m_name);
|
|
_spoFile.OutLine(currentCmd);
|
|
|
|
sprintf(currentCmd, "\tPutMatrix(\"*^Matrix:%s\")", m_name);
|
|
_spoFile.OutLine(currentCmd);
|
|
|
|
if (GetGeomLink())
|
|
{
|
|
sprintf(currentCmd, "\t%s", GetGeomLink());
|
|
_spoFile.OutLine(currentCmd);
|
|
}
|
|
|
|
for ( Iter = m_childs.begin( ); Iter != m_childs.end( ); Iter++ )
|
|
{
|
|
CSuperObject *spo = *Iter;
|
|
sprintf(currentCmd, "\tAddChild(\"*^SuperObject:%s\")", spo->m_name);
|
|
_spoFile.OutLine(currentCmd);
|
|
}
|
|
_spoFile.OutLine("}\n");
|
|
|
|
// dump matrix
|
|
|
|
sprintf(currentCmd, "{Matrix:%s", m_name);
|
|
_spoFile.OutLine(currentCmd);
|
|
|
|
Matrix3 NodMat;
|
|
GetLocalMatrix(NodMat, _time);
|
|
|
|
Point3 pos = NodMat.GetTrans();
|
|
|
|
sprintf(currentCmd, "\tMatrixTranslation(\"%g\",\"%g\",\"%g\")", pos.x, pos.y, pos.z);
|
|
_spoFile.OutLine(currentCmd);
|
|
/*
|
|
Quat quat = node->GetObjOffsetRot();
|
|
Matrix3 RotMat;
|
|
quat.MakeMatrix(RotMat);
|
|
ScaleValue scaleValue = node->GetObjOffsetScale();
|
|
*/
|
|
_spoFile.OutLine("}\n");
|
|
|
|
// dump childs
|
|
for ( Iter = m_childs.begin( ); Iter != m_childs.end( ); Iter++ )
|
|
{
|
|
CSuperObject *spo = *Iter;
|
|
spo->DumpSpo(_spoFile, _time);
|
|
}
|
|
|
|
}
|
|
void CSuperObject::GetLocalMatrix(Matrix3 &_NodMat, TimeValue _time)
|
|
{
|
|
if (m_maxNode != NULL)
|
|
{
|
|
_NodMat = m_maxNode->GetNodeTM(_time);
|
|
}
|
|
else
|
|
{
|
|
_NodMat = Matrix3(true);
|
|
}
|
|
if ((m_Parent != NULL) && (m_Parent->m_maxNode != NULL))
|
|
{
|
|
Matrix3 temp = _NodMat;
|
|
Matrix3 ip = Inverse(m_Parent->m_maxNode->GetNodeTM(_time));
|
|
_NodMat = ip * temp;
|
|
}
|
|
}
|