2025-02-17 23:17:30 -06:00

649 lines
18 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#pragma pack(push,8)
#include <MAX.H>
#pragma pack(pop)
// NOTE:
// if you have problems linking this exporter it is likely you are encountering a
// bug in Microsofts include\basetsd.h header.
//
// The problem is that Visual C++ defines INT_PTR to 'long' when it is
// supposed to be defined as an 'int' (on ia32 platforms). You can either
// use a supported build environment by updating to the platform SDK, or
// you can use the unsupported environment by manually fixing the problem
// in the header "On or around line 123 of include\basetsd.h change:
//
// typedef long INT_PTR, *PINT_PTR;
// typedef unsigned long UINT_PTR, *PUINT_PTR;
// TO
// typedef int INT_PTR, *PINT_PTR;
// typedef unsigned int UINT_PTR, *PUINT_PTR;
#include "max2dtsExporter/exporter.h"
#include "max2dtsExporter/sceneEnum.h"
#include "core/filestream.h"
#include "ts/tsShapeInstance.h"
#include "max2dtsExporter/sequence.h"
#include "max2dtsExporter/exportUtil.h"
#include "max2dtsExporter/skinHelper.h"
#define DLLEXPORT __declspec(dllexport)
#if defined(TORQUE_DEBUG)
const char * const gProgramVersion = "0.900d-beta";
#else
const char * const gProgramVersion = "0.900r-beta";
#endif
HINSTANCE hInstance;
S32 gSupressUI = 0;
TCHAR maxFile[1024];
S32 controlsInit = FALSE;
char dllPath[256];
char globalConfig[270];
TCHAR *GetString(S32 id)
{
static TCHAR buf[256];
if (hInstance)
{
return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL;
}
return NULL;
}
const char * days[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
const char * months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
static S32 Alert(const char * s1, const char * s2, S32 option = MB_OK)
{
if (gSupressUI)
{
FileStream fs;
fs.open(avar("%smax2difExport.error.log",dllPath),FileStream::ReadWrite);
if (fs.getStatus() != Stream::Ok)
{
fs.close();
return -1;
}
fs.setPosition(fs.getStreamSize());
// what's the time and date?
Platform::LocalTime localTime;
Platform::getLocalTime(localTime);
char timeBuffer[256];
dStrcpy(timeBuffer,avar("%i:%i on %s %s %i",localTime.hour,localTime.min,days[localTime.weekday],months[localTime.month],localTime.monthday));
// write the error to the log file
char buffer[1024];
dStrcpy(buffer,avar("Error exporting file \"%s\" at %s:\r\n --> %s\r\n\r\n",maxFile,timeBuffer,s1));
fs.writeLine((unsigned char*) buffer);
fs.close();
return -1;
}
else
{
TSTR str1(s1);
TSTR str2(s2);
return MessageBox(GetActiveWindow(), str1, str2, option);
}
}
static S32 Alert(S32 s1, S32 s2 = IDS_TH_DTSEXP, S32 option = MB_OK)
{
return Alert(GetString(s1),GetString(s2),option);
}
static S32 Alert(const char * s1, S32 s2 = IDS_TH_DTSEXP, S32 option = MB_OK)
{
return Alert(s1,GetString(s2),option);
}
const char * GetVersionString()
{
static char versionString[128];
dStrcpy(versionString,avar("Version %s (dts v%i.%.2i)",gProgramVersion, DTS_EXPORTER_CURRENT_VERSION/100, DTS_EXPORTER_CURRENT_VERSION%100));
return versionString;
}
//------------------------------------------------------
// Our main plugin class:
class _Exporter : public SceneExport
{
char extension[10]; // 'DTS' or 'DSQ'
public:
_Exporter(const char *);
~_Exporter();
S32 ExtCount(); // Number of extensions supported
const TCHAR *Ext(S32); // Extension #n
const TCHAR *LongDesc(); // Long ASCII description
const TCHAR *ShortDesc(); // Short ASCII description
const TCHAR *AuthorName(); // ASCII Author name
const TCHAR *CopyrightMessage(); // ASCII Copyright message
const TCHAR *OtherMessage1(); // Other message #1
const TCHAR *OtherMessage2(); // Other message #2
U32 Version(); // Version number * 100
void ShowAbout(HWND); // Show DLL's "About..." box
S32 DoExport(const TCHAR *, ExpInterface *, Interface *, int, DWORD);
};
//------------------------------------------------------
// Jaguar interface code
extern void mInstallLibrary_C();
namespace Memory
{
extern bool gAlwaysLogLeaks;
};
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
{
hInstance = hinstDLL;
if (!controlsInit)
{
controlsInit = TRUE;
// 3DS custom controls
InitCustomControls(hInstance);
// Initialize common Windows controls
InitCommonControls();
// install math library (set up function pointers)
mInstallLibrary_C();
// set "factory" default parameter values
SceneEnumProc::setInitialDefaults();
// always log memory leaks -- some of them aren't really leaks,
// but we want to see them and we don't want the annoying box asking us
// about it...
Memory::gAlwaysLogLeaks = true;
// get DLL path
GetModuleFileName(hInstance,dllPath,sizeof(dllPath));
char * p = dStrrchr(dllPath,'\\');
char * p2 = dStrrchr(dllPath,':');
if (p && *p=='\\')
*(p+1) = '\0';
else if(p2 && *p2==':')
*(p2+1) = '\0';
else
dllPath[0] = '\0';
// load the global config file if we can find it
dStrcpy(globalConfig,dllPath);
dStrcpy(globalConfig+dStrlen(globalConfig),"dtsGlobal.cfg");
SceneEnumProc::readConfigFile(globalConfig);
}
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return(TRUE);
}
// defines for setting exporter type and description
#define _EXPORTER_CLASS_NAME "Torque Shape Exporter"
#define _DTS_EXPORTER_CLASS_ID Class_ID(0x296a4787, 0x2ec557fc)
#define _DSQ_EXPORTER_CLASS_ID Class_ID(0x65d74e76, 0x10da4a97)
#define _TXT_EXPORTER_CLASS_ID Class_ID(0x6bfb02d7, 0x13860666)
#define _EXPORTER_CLASS_SDESC "Torque Shape Exporter"
// more code for interfacing with max
class _DTSClassDesc : public ClassDesc
{
public:
S32 IsPublic() { return 1; }
void *Create(BOOL loading = FALSE) { return new _Exporter("DTS"); }
const TCHAR *ClassName() { return _EXPORTER_CLASS_NAME; }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return _DTS_EXPORTER_CLASS_ID; }
const TCHAR *Category() { return GetString(IDS_TH_SHAPEEXPORT); }
};
// more code for interfacing with max
class _DSQClassDesc : public ClassDesc
{
public:
S32 IsPublic() { return 1; }
void *Create(BOOL loading = FALSE) { return new _Exporter("DSQ"); }
const TCHAR *ClassName() { return _EXPORTER_CLASS_NAME; }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return _DSQ_EXPORTER_CLASS_ID; }
const TCHAR *Category() { return GetString(IDS_TH_SHAPEEXPORT); }
};
// more code for interfacing with max
class _TXTClassDesc : public ClassDesc
{
public:
S32 IsPublic() { return 1; }
void *Create(BOOL loading = FALSE) { return new _Exporter("TXT"); }
const TCHAR *ClassName() { return _EXPORTER_CLASS_NAME; }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return _TXT_EXPORTER_CLASS_ID; }
const TCHAR *Category() { return GetString(IDS_TH_SHAPEEXPORT); }
};
static _DTSClassDesc _DTSDesc;
static _DSQClassDesc _DSQDesc;
static _TXTClassDesc _TXTDesc;
DLLEXPORT const TCHAR *LibDescription()
{
return GetString(IDS_TH_DTSEXPORTDLL);
}
DLLEXPORT S32 LibNumberClasses()
{
return 6;
}
DLLEXPORT ClassDesc *LibClassDesc(S32 i)
{
switch(i)
{
case 0:
return &_DTSDesc;
case 1:
return &_DSQDesc;
case 2:
return &_TXTDesc;
case 3:
return GetSequenceDesc();
case 4:
return GetExportUtilDesc();
case 5:
return GetSkinHelperDesc();
default:
return NULL;
}
}
// Return version so can detect obsolete DLLs
DLLEXPORT ULONG LibVersion()
{
return VERSION_3DSMAX;
}
//
// ._DTS export module functions follow:
//
_Exporter::_Exporter(const char * _extension)
{
dStrcpy(extension,_extension);
}
_Exporter::~_Exporter()
{
}
S32 _Exporter::ExtCount()
{
return 1;
}
// Extensions supported for import/export modules
const TCHAR *_Exporter::Ext(S32 n)
{
switch(n)
{
case 0:
return _T(extension);
default:
return _T("");
}
}
// Long ASCII description (e.g., "Targa 2.0 Image File")
const TCHAR *_Exporter::LongDesc()
{
return GetString(IDS_TH_DTSFILE_LONG);
}
// Short ASCII description (e.g., "Targa")
const TCHAR *_Exporter::ShortDesc()
{
return _EXPORTER_CLASS_SDESC;
}
// ASCII Author name
const TCHAR *_Exporter::AuthorName()
{
return GetString(IDS_TH_AUTHOR);
}
// ASCII Copyright message
const TCHAR *_Exporter::CopyrightMessage()
{
return GetString(IDS_TH_COPYRIGHT_COMPANY);
}
// Other message #1
const TCHAR *_Exporter::OtherMessage1()
{
return _T("");
}
// Other message #2
const TCHAR *_Exporter::OtherMessage2()
{
return _T("");
}
// Version number * 100 (i.e. v3.01 = 301)
U32 _Exporter::Version()
{
return DTS_EXPORTER_CURRENT_VERSION;
}
// Optional
void _Exporter::ShowAbout(HWND hWnd)
{
}
//------------------------------------------------------
// be more thourough about this later...
U32 saveDumpMask;
bool saveEnableSequences;
bool saveCollapse;
bool saveAllowEmptySubtrees;
bool saveAllowCrossedDetails;
bool saveAllowUnusedMeshes;
bool saveViconNeeded;
bool saveAllowOldSequences;
F32 saveAnimationDelta;
F32 saveMaxFrameRate;
S32 saveT2AutoDetail;
void saveConfig()
{
saveDumpMask = dumpMask;
saveEnableSequences = enableSequences;
saveCollapse = transformCollapse;
saveAllowEmptySubtrees = allowEmptySubtrees;
saveAllowCrossedDetails = allowCrossedDetails;
saveAllowUnusedMeshes = allowUnusedMeshes;
saveViconNeeded = viconNeeded;
saveAllowOldSequences = allowOldSequences;
saveAnimationDelta = animationDelta;
saveMaxFrameRate = maxFrameRate;
saveT2AutoDetail = t2AutoDetail;
}
void restoreConfig()
{
dumpMask = saveDumpMask;
enableSequences = saveEnableSequences;
transformCollapse = saveCollapse;
allowEmptySubtrees = saveAllowEmptySubtrees;
allowCrossedDetails = saveAllowCrossedDetails;
allowUnusedMeshes = saveAllowUnusedMeshes;
viconNeeded = saveViconNeeded;
allowOldSequences = saveAllowOldSequences;
animationDelta = saveAnimationDelta;
maxFrameRate = saveMaxFrameRate;
t2AutoDetail = saveT2AutoDetail;
}
S32 cheapSemaphore = 0;
S32 _dts_save(const TCHAR *fname, ExpInterface *ei, Interface *gi)
{
if (cheapSemaphore)
{
Alert("One export at a time: Export code not re-entrant.");
return 1;
}
cheapSemaphore = 1;
char filename[1024];
dStrcpy(filename,fname);
char * ch = filename;
while (*ch!='\0')
{
*ch = tolower(*ch);
ch++;
}
SceneEnumProc myScene;
dStrcpy(maxFile,gi->GetCurFilePath());
//-----------------------------------------------
// read in the config file...
char configFilename[256];
dStrcpy(configFilename,maxFile);
char * p = dStrrchr(configFilename,'\\');
char * p2 = dStrrchr(configFilename,':');
if (p && *p=='\\')
dStrcpy(p+1,"*.cfg");
else if (p2 && *p2==':')
dStrcpy(p2+1,"*.cfg");
else
dStrcpy(configFilename,"*.cfg");
const char * error = myScene.readConfigFile(configFilename);
if (error)
myScene.setExportError(error);
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// create dump file...
myScene.startDump(filename,maxFile);
//-----------------------------------------------
// read config file again so we have a record of it...
myScene.readConfigFile(configFilename);
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// tweak some parameters depending on export type...
if (dStrstr((const char*)filename,".dsq"))
{
// we're exporting sequences, so turn this on
if (!enableSequences)
{
enableSequences = true;
SceneEnumProc::printDump(PDAlways,"\r\nEnabling \"Param::SequenceExport\" (doing *.dsq export).\r\n");
}
SceneEnumProc::exportType = 's'; // sequence
}
if (dStrstr((const char*)filename,".txt"))
{
// doing a text file dump -- export everything
if (!enableSequences)
{
enableSequences = true;
SceneEnumProc::printDump(PDAlways,"\r\nEnabling \"Param::SequenceExport\" (doing *.txt export).\r\n");
}
if (transformCollapse)
{
transformCollapse = false;
SceneEnumProc::printDump(PDAlways,"\r\nDisabling \"Param::CollapseTransforms\" (doing *.txt export).\r\n");
}
SceneEnumProc::exportType = 't'; // text
}
if (dStrstr((const char*)filename,".dts"))
SceneEnumProc::exportType = 'w'; // whole shape
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// Get the nodes we're interested in!
// We also do some checking to make sure everything
// we need is present ... if something is missing,
// an error will be returned.
myScene.enumScene(ei->theScene);
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// Any useful nodes?
if (myScene.isEmpty())
{
Alert("No data to export");
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// make sure we get rid of target file before opening it
// otherwise, it'll never shrink
File zap;
zap.open(filename,File::Write);
zap.close();
//-----------------------------------------------
// open a file to save the exported shape to:
FileStream file;
file.open(filename,FileStream::Write);
if( file.getStatus() != Stream::Ok )
{
Alert(IDS_TH_CANTCREATE);
cheapSemaphore = 0;
return(0);
}
//-----------------------------------------------
// actually do the export:
myScene.processScene();
//-----------------------------------------------
// Error?
if (myScene.isExportError())
{
Alert(myScene.getExportError());
file.close();
cheapSemaphore = 0;
return 1;
}
//-----------------------------------------------
// now save the shape
TSShape * pShape = myScene.getShape();
if (dStrstr((const char*)filename,".dts"))
pShape->write(&file);
else if (dStrstr((const char*)filename,".dsq"))
pShape->exportSequences(&file);
else if (dStrstr((const char*)filename,".txt"))
myScene.exportTextFile(&file);
//-----------------------------------------------
// close the file and report any problems:
if( file.getStatus() != Stream::Ok )
{
Alert(IDS_TH_WRITEERROR);
file.close();
remove(filename);
cheapSemaphore = 0;
return(0);
}
else
file.close();
//-----------------------------------------------
// write the shape out to dump file
if (PDShapeHierarchy & dumpMask && dStrstr((const char*)filename,".dts"))
{
// write out the structure of the newly created shape
// but read it from the file first...
if (!SceneEnumProc::dumpShape(filename))
{
Alert(avar("Error opening created file \"%s\".",filename));
file.close();
cheapSemaphore = 0;
return 1;
}
}
cheapSemaphore = 0;
return 1;
}
S32 _Exporter::DoExport(const TCHAR *filename,ExpInterface *ei,Interface *gi, S32 supressUI, DWORD)
{
gSupressUI = supressUI;
// so we can go back to defaults when we're done
saveConfig();
S32 status;
status = _dts_save(filename, ei, gi);
restoreConfig();
if(status == 0)
return 1; // Dialog cancelled
if(status < 0)
return 0; // Real, honest-to-goodness error
return status;
}