You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

394 lines
10 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//
// 3DSMax HeadSpin exporter
//
#include "HeadSpin.h"
#include "SimpleExport.h"
#include "notify.h"
#include "plExportErrorMsg.h"
#include "plExportLogErrorMsg.h"
#include "MaxConvert/UserPropMgr.h"
#include "hsExceptionStack.h"
#include "MaxConvert/hsConverterUtils.h"
#include "MaxConvert/plBitmapCreator.h"
#include "pfPython/plPythonFileMod.h"
#include "MaxMain/plPluginResManager.h"
#include "plResMgr/plRegistryHelpers.h"
#include "plResMgr/plRegistryNode.h"
#include "hsStream.h"
#include "MaxConvert/plConvert.h"
#include "MaxConvert/hsMaterialConverter.h"
#include "plPhysX/plSimulationMgr.h"
#include "plSDL/plSDL.h"
#include "MaxMain/plMaxCFGFile.h"
// For texture export/cleanup
#include "MaxMain/plTextureExportLog.h"
#include "pnKeyedObject/plKey.h"
#include "pnKeyedObject/plUoid.h"
#include "plGImage/plCubicEnvironmap.h"
#include "plGImage/plDynamicTextMap.h"
#include "plGImage/plMipmap.h"
#include "plScene/plSceneNode.h"
#include "plExportDlg.h"
#include "plStatusLog/plStatusLog.h"
#include "plFile/plFileUtils.h"
#include "plAvatar/plAvatarMgr.h"
extern UserPropMgr gUserPropMgr;
#ifdef HS_DEBUGGING
#define HS_NO_TRY
#endif
//
// .MSH export module functions follow:
//
HSExport2::HSExport2()
{
}
HSExport2::~HSExport2()
{
}
int HSExport2::ExtCount()
{
return 2;
}
//
// Extensions supported for import/export modules
//
const TCHAR *HSExport2::Ext(int n)
{
static char str[64];
switch(n)
{
case 0:
return "";
case 1:
return "prd";
}
return _T("");
}
//
// Long ASCII description (i.e. "Targa 2.0 Image File")
//
const TCHAR *HSExport2::LongDesc()
{
return "Plasma 2.0";
}
//
// Short ASCII description (i.e. "Targa")
//
const TCHAR *HSExport2::ShortDesc()
{
#ifdef HS_DEBUGGING
return "Plasma 2.0 Debug";
#else
return "Plasma 2.0";
#endif
}
//
// ASCII Author name
//
const TCHAR *HSExport2::AuthorName()
{
return "Billy Bob";
}
//
// ASCII Copyright message
//
const TCHAR *HSExport2::CopyrightMessage()
{
return "Copyright 1997 HeadSpin Technology Inc.";
}
//
// Other message #1
//
const TCHAR *HSExport2::OtherMessage1()
{
return _T("");
}
//
// Other message #2
//
const TCHAR *HSExport2::OtherMessage2()
{
return _T("");
}
//
// Version number * 100 (i.e. v3.01 = 301)
//
unsigned int HSExport2::Version()
{
return 100;
}
//
// Optional
//
void HSExport2::ShowAbout(HWND hWnd)
{
}
void IGetPath(const char* name, char* path)
{
int i;
// find the last backslash in the full path
for ( i=strlen(name)-1; i>=0 ; i-- )
{
if ( name[i] == '\\' )
break;
}
if ( i >= 0 && i < 256) // if either we couldn't the backslash or the path was too big
{
strncpy(path,name,i+1);
path[i+1] = '\0'; //null terminate string (cause strncpy might not)
}
else
path[0] = '\0'; // otherwise just make it a null string
}
// Another little helper class to help write out a list of textures to a log file
class plTextureLoggerCBack : public plRegistryKeyIterator
{
protected:
plTextureExportLog* fTELog;
public:
plTextureLoggerCBack(plTextureExportLog* teLog) { fTELog = teLog; }
virtual hsBool EatKey(const plKey& key)
{
plBitmap* bmap = plBitmap::ConvertNoRef(key->ObjectIsLoaded());
if (bmap != nil)
fTELog->AddTexture(bmap);
return true; // Always continue
}
};
// Yet another key iterator, this one to call OptimizeDrawables() on each sceneNode
class plOptimizeIterator : public plRegistryKeyIterator
{
public:
virtual hsBool EatKey(const plKey& key)
{
if (key->GetUoid().GetClassType() == plSceneNode::Index())
{
plSceneNode* sn = plSceneNode::ConvertNoRef(key->ObjectIsLoaded());
if (sn != nil)
sn->OptimizeDrawables();
}
return true; // Always continue
}
};
//
//
//
int HSExport2::DoExport(const TCHAR *name,ExpInterface *ei,Interface *gi, BOOL suppressPrompts, DWORD options)
{
BOOL backupEnabled = gi->AutoBackupEnabled();
gi->EnableAutoBackup(FALSE);
BOOL bmmSilentMode = TheManager->SilentMode();
TheManager->SetSilentMode(TRUE);
bool mbSuppressPrompts = hsMessageBox_SuppressPrompts;
hsMessageBox_SuppressPrompts = (suppressPrompts)?true:false;
// Disable save so we don't crash in export or
// otherwise screw database.
SimpleExportExitCallback exitCB;
gi->RegisterExitMAXCallback(&exitCB);
gUserPropMgr.OpenQuickTable();
hsConverterUtils::Instance().CreateNodeSearchCache();
BroadcastNotification(NOTIFY_PRE_EXPORT);
// get just the path (not the file) of where we are going to export to
char out_path[256];
IGetPath(name, out_path);
// Apparently this was implied by the open dialog, but not if you call Max's ExportToFile() func
SetCurrentDirectory(out_path);
//
// Setup ErrorMsg
//
// Needs to be outside try/catch so it doesn't stack unwind...
plExportErrorMsg hituser_errorMessage; // This is the errorMessage that slaps user
TSTR filename = gi->GetCurFileName();
hsStrncpy(fName, filename, 128);
char *dot = strrchr(fName, '.');
if (dot)
*dot = 0;
char ErrorLogName[512];
sprintf(ErrorLogName, "%s%s.err", out_path, fName);
plExportLogErrorMsg logonly_errorMessage(ErrorLogName); // This errorMessage just writes it all to a file
// now decide which errorMessage object to use
plErrorMsg* errorMessage;
if (suppressPrompts)
errorMessage = &logonly_errorMessage;
else
errorMessage = &hituser_errorMessage;
// For export time stats
DWORD exportTime = timeGetTime();
_SYSTEMTIME tm;
GetSystemTime(&tm);
//
// Let's get cracking! Convert the scene...
//
plConvertSettings settings;
if (plExportDlg::Instance().IsExporting())
{
settings.fDoPreshade = plExportDlg::Instance().GetDoPreshade();
settings.fPhysicalsOnly = plExportDlg::Instance().GetPhysicalsOnly();
settings.fDoLightMap = plExportDlg::Instance().GetDoLightMap();
settings.fExportPage = plExportDlg::Instance().GetExportPage();
}
plConvert::Instance().Init(gi, errorMessage, &settings);
// We want to incorporate any SDL changes since the last export, so we DeInit()
// and re-initialize.
char buf[MAX_PATH];
strcpy(buf, plMaxConfig::GetClientPath());
strcat(buf, "sdl");
plSDLMgr::GetInstance()->SetSDLDir(buf);
plSDLMgr::GetInstance()->DeInit();
plSDLMgr::GetInstance()->Init();
// Add disk source for writing
char datPath[MAX_PATH];
strcpy(datPath, out_path);
plFileUtils::AddSlash(datPath);
strcat(datPath, "dat\\");
CreateDirectory(datPath, NULL);
plPluginResManager::ResMgr()->SetDataPath(datPath);
if (hsgResMgr::Reset())
{
plSimulationMgr::Init();
plAvatarMgr::GetInstance();
// Verify the pages here manually, since it's a separate step now
plPluginResManager::ResMgr()->VerifyPages();
plPythonFileMod::SetAtConvertTime();
// Convert!!!
hsBool convertOK = plConvert::Instance().Convert();
// Free the material cache. This will delete unused materials.
hsMaterialConverter::Instance().FreeMaterialCache(out_path);
if (convertOK)
{
// Optimize the drawables
plOptimizeIterator optIterator;
plPluginResManager::ResMgr()->IterateKeys( &optIterator );
// And save.
plPluginResManager::ResMgr()->WriteAllPages();
// Write out a texture log file
char textureLog[MAX_PATH];
sprintf(textureLog, "log\\exportedTextures_%s.log", fName);
plTextureExportLog textureExportLog( textureLog );
plTextureLoggerCBack loggerCallback( &textureExportLog );
plPluginResManager::ResMgr()->IterateKeys( &loggerCallback );
textureExportLog.Write();
// Moving this to the end of writing the files out. Yes, this means that any unused mipmaps still get
// written to disk, including ones loaded on preload, but it's the only way to get shared texture pages
// to work without loading in the entire age worth of reffing objects. - 5.30.2002 mcn
plBitmapCreator::Instance().DeInit();
}
// Have the resMgr clean up after export. This includes paging out any converted pages
plPluginResManager::ResMgr()->EndExport();
plSimulationMgr::Shutdown();
plAvatarMgr::ShutDown();
// Reset the resmgr so we free all the memory it allocated
hsgResMgr::Reset();
}
//----------------------------------------------
// Write a log entry to the Db file name for now
//----------------------------------------------
hsUNIXStream dbLog;
dbLog.Open(name,"at");
char str[256];
exportTime = (timeGetTime() - exportTime) / 1000;
sprintf(str,"Export from Max File \"%s\" on %02d/%02d/%4d took %d:%02d\n",filename,tm.wMonth,tm.wDay,tm.wYear, exportTime/60, exportTime%60);
dbLog.WriteString(str);
dbLog.Close();
// Allow plugins to clean up after export
BroadcastNotification(NOTIFY_POST_EXPORT);
hsConverterUtils::Instance().DestroyNodeSearchCache();
gUserPropMgr.CloseQuickTable();
gi->UnRegisterExitMAXCallback(&exitCB);
hsMessageBox_SuppressPrompts = mbSuppressPrompts;
TheManager->SetSilentMode(bmmSilentMode);
gi->EnableAutoBackup(backupEnabled);
MessageBeep(MB_ICONASTERISK);
return 1;
}