Redone max exporter as a plugin rather than an export menu option

This commit is contained in:
Philip Saltzman 2005-05-12 20:46:28 +00:00
parent e9bb1ee965
commit e558fae66f
15 changed files with 2128 additions and 678 deletions

View File

@ -13,7 +13,7 @@
#include "MaxEgg.h"
extern ClassDesc2* GetMaxEggPluginDesc();
extern ClassDesc* GetMaxEggPluginDesc();
HINSTANCE hInstance;
int controlsInit = FALSE;

View File

@ -19,46 +19,53 @@
#include <crtdbg.h>
// Discreet-Generated ID for this app.
#define MaxEggPlugin_CLASS_ID Class_ID(0x7ac0d6b7, 0x55731ef6)
// Our version number * 100
#define MAX_EGG_VERSION_NUMBER 100
#define MNEG Logger::ST_MAP_ME_TO_APP_SPECIFIC_SYSTEM2
#define MNEG_GEOMETRY_GENERATION Logger::ST_MAP_ME_TO_APP_SPECIFIC_SYSTEM3
//Disable the forcing int to true or false performance warning
#pragma warning(disable: 4800)
/* MaxEggPluginClassDesc - A class that describes 3DS Plugin support.
This basically says "Yes, I can export files. Use me!"
This basically says "Yes, I am a helper object!"
*/
class MaxEggPluginClassDesc:public ClassDesc2
class MaxEggPluginClassDesc : public ClassDesc
{
public:
int IsPublic() { return TRUE; }
void *Create(BOOL loading = FALSE) { return new MaxEggPlugin(); }
const TCHAR *ClassName() { return GetString(IDS_CLASS_NAME); }
SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
Class_ID ClassID() { return MaxEggPlugin_CLASS_ID; }
const TCHAR *Category() { return GetString(IDS_CATEGORY); }
int IsPublic() { return TRUE; }
void *Create(BOOL loading = FALSE) { return new MaxEggPlugin(); }
const TCHAR *ClassName() { return GetString(IDS_CLASS_NAME); }
SClass_ID SuperClassID() { return HELPER_CLASS_ID; }
Class_ID ClassID() { return MaxEggPlugin_CLASS_ID; }
const TCHAR *Category() { return GetString(IDS_CATEGORY); }
// returns fixed parsable name (scripter-visible name)
const TCHAR *InternalName() { return _T("MaxEggPlugin"); }
// returns owning module handle
HINSTANCE HInstance() { return hInstance; }
};
// Our static instance of the above class
// Our private global instance of the above class
static MaxEggPluginClassDesc MaxEggPluginDesc;
// The function that I believe Max calls, when looking for information as
// to what this plugin does.
ClassDesc2* GetMaxEggPluginDesc() { return &MaxEggPluginDesc; }
// Called by LibClassDesc to find out what the plugin is
ClassDesc* GetMaxEggPluginDesc() { return &MaxEggPluginDesc; }
// Initialize class-static variables
Mesh MaxEggPlugin::mesh;
short MaxEggPlugin::meshBuilt=0;
HWND MaxEggPlugin::hMaxEggParams = NULL;
IObjParam *MaxEggPlugin::iObjParams;
/* MaxEggPluginOptionsDlgProc() - This is the callback function for the
dialog box that appears at the beginning of the conversion process.
*/
BOOL CALLBACK MaxEggPluginOptionsDlgProc( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
MaxEggExpOptions *tempEgg;
int sel, res;
//We pass in our plugin through the lParam variable. Let's convert it back.
MaxEggPlugin *imp = (MaxEggPlugin*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
if ( !imp && message != WM_INITDIALOG ) return FALSE;
switch(message)
{
@ -66,345 +73,459 @@ BOOL CALLBACK MaxEggPluginOptionsDlgProc( HWND hWnd, UINT message,
case WM_INITDIALOG:
// this line is very necessary to pass the plugin as the lParam
SetWindowLongPtr(hWnd,GWLP_USERDATA,lParam);
CenterWindow(hWnd,GetParent(hWnd));
return TRUE;
break;
// Closing the window is equivalent to canceling the export
case WM_CLOSE:
imp->confirmExport = false;
EndDialog(hWnd, 0);
return TRUE;
break;
// If we get here, this means thatone of our controls was modified.
SetDlgFont( hWnd, imp->iObjParams->GetAppHFont() );
MaxEggPlugin::hMaxEggParams = hWnd;
return TRUE; break;
case WM_MOUSEACTIVATE:
imp->iObjParams->RealizeParamPanel();
return TRUE; break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
imp->iObjParams->RollupMouseMessage(hWnd,message,wParam,lParam);
return TRUE; break;
// A control was modified
case WM_COMMAND:
//The control in question will be found in the lower word of the wParam
// long.
switch( LOWORD(wParam) )
{
// The checkbox for toggling whether this model has animations
case IDC_ANIMATION:
// sets the plugin's animation parameter
imp->animation = !imp->animation;
CheckDlgButton( hWnd, IDC_ANIMATION,
imp->animation ? BST_CHECKED : BST_UNCHECKED );
// Enables/disables the animation options depending on how the
// animation checkbox is checked
EnableWindow(GetDlgItem(hWnd, IDC_MODEL), imp->animation);
EnableWindow(GetDlgItem(hWnd, IDC_CHAN), imp->animation);
EnableWindow(GetDlgItem(hWnd, IDC_POSE), imp->animation);
EnableWindow(GetDlgItem(hWnd, IDC_STROBE), imp->animation);
EnableWindow(GetDlgItem(hWnd, IDC_BOTH), imp->animation);
EnableWindow(GetDlgItem(hWnd, IDC_SF), imp->animation);
EnableWindow(GetDlgItem(hWnd, IDC_EF), imp->animation);
// if this is the first time the animation checkbox has been checked,
// then there is no animation type set, so set the animation type to
// "model"
if (imp->anim_type == MaxEggPlugin::AT_none) {
CheckDlgButton( hWnd, IDC_MODEL, BST_CHECKED );
imp->anim_type = MaxEggPlugin::AT_model;
}
return TRUE;
break;
// The radio buttons for what type of animation will exported
// The animation type is set by these buttons
case IDC_MODEL:
imp->anim_type = MaxEggPlugin::AT_model;
break;
case IDC_CHAN:
imp->anim_type = MaxEggPlugin::AT_chan;
break;
case IDC_POSE:
imp->anim_type = MaxEggPlugin::AT_pose;
break;
case IDC_STROBE:
imp->anim_type = MaxEggPlugin::AT_strobe;
break;
case IDC_BOTH:
imp->anim_type = MaxEggPlugin::AT_both;
break;
//The checkbox that toggles wether to make a .BAM file or not.
case IDC_MAKE_BAM:
imp->makeBam = !imp->makeBam;
CheckDlgButton( hWnd, IDC_MAKE_BAM,
imp->makeBam ? BST_CHECKED : BST_UNCHECKED );
return TRUE;
break;
// Ckicking the cancel button obviously cancels the export
case IDC_CANCEL:
imp->confirmExport = false;
EndDialog(hWnd, 0);
return TRUE;
break;
// Clicking the done button is the only way to continue with the export
case IDC_DONE:
imp->confirmExport = true;
EndDialog(hWnd, 0);
return TRUE;
break;
}
break;
//The modified control is found in the lower word of the wParam long.
switch( LOWORD(wParam) ) {
case IDC_OVERWRITE_CHECK:
imp->autoOverwrite =
(IsDlgButtonChecked(hWnd, IDC_OVERWRITE_CHECK) == BST_CHECKED);
return TRUE; break;
case IDC_PVIEW_CHECK:
imp->pview =
(IsDlgButtonChecked(hWnd, IDC_PVIEW_CHECK) == BST_CHECKED);
return TRUE; break;
case IDC_LOGGING:
imp->logOutput =
(IsDlgButtonChecked(hWnd, IDC_LOGGING) == BST_CHECKED);
return TRUE; break;
case IDC_ADD_EGG:
tempEgg = new MaxEggExpOptions();
tempEgg->maxInterface = imp->iObjParams;
tempEgg->SetAnimRange();
res = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EGG_DETAILS),
hWnd, MaxEggExpOptionsProc, (LPARAM)tempEgg);
tempEgg->maxInterface = NULL;
if (res == TRUE) {
imp->SaveCheckState();
imp->AddEgg(tempEgg);
imp->UpdateUI();
}
else delete tempEgg;
return TRUE; break;
case IDC_EDIT_EGG:
sel = ListView_GetSelectionMark(GetDlgItem(hWnd, IDC_LIST_EGGS));
if (sel != -1) {
MaxEggExpOptions *tempEgg = imp->GetEgg(sel);
if (tempEgg) {
tempEgg->maxInterface = imp->iObjParams;
tempEgg->SetAnimRange();
tempEgg->CullBadNodes();
DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EGG_DETAILS),
hWnd, MaxEggExpOptionsProc, (LPARAM)tempEgg);
tempEgg->maxInterface = NULL;
}
imp->SaveCheckState();
imp->UpdateUI();
}
return TRUE; break;
case IDC_REMOVE_EGG:
sel = ListView_GetSelectionMark(GetDlgItem(hWnd, IDC_LIST_EGGS));
if (sel != -1) {
imp->SaveCheckState();
imp->RemoveEgg(sel);
imp->UpdateUI();
}
return TRUE; break;
case IDC_EXPORT:
imp->DoExport();
return TRUE; break;
}
}
return FALSE;
}
/* MaxEggPlugin() - Uninteresting constructor.
*/
MaxEggPlugin::MaxEggPlugin()
MaxEggPlugin::MaxEggPlugin() :
autoOverwrite(false), pview(true), logOutput(false), numEggs(0), maxEggs(5)
{
makeBam = false;
animation = false;
anim_type = AT_none;
eggList = new MaxEggExpOptions*[maxEggs];
BuildMesh();
}
/* ~MaxEggPlugin() - Uninteresting destructor.
*/
MaxEggPlugin::~MaxEggPlugin()
{
MaxEggPlugin::~MaxEggPlugin() {
for (int i = 0; i < numEggs; i++) delete eggList[i];
delete [] eggList;
}
/* ExtCount() - Returns the number of extensions this exporter produces.
That's only one, .EGG files.
*/
int MaxEggPlugin::ExtCount()
{
return 1;
}
/* Ext(int) - Returns the nth extension. Since there's only one, it always
returns "egg"
*/
const TCHAR *MaxEggPlugin::Ext(int n)
{
return _T("egg");
}
/* LongDesc() - A long description of the files we export. Curiously, this
isn't for the nth extension, rather a one-description-fits-all thing.
*/
const TCHAR *MaxEggPlugin::LongDesc()
{
return _T("Panda3D .egg file");
}
/**
* A short description of the files we export. Curiously, this isn't
* for the nth extension, rather a one-description-fits-all thing.
*/
const TCHAR *MaxEggPlugin::ShortDesc()
{
return _T("Panda3D");
}
/**
* Who wrote this.
*/
const TCHAR *MaxEggPlugin::AuthorName()
{
return _T("Steven \"Sauce\" Osman");
}
/**
* Who owns this.
*/
const TCHAR *MaxEggPlugin::CopyrightMessage()
{
return _T("Copyright (C) 2003 Carnegie Mellon University, Entertainment Technology Center");
}
/**
* Who cares?
*/
const TCHAR *MaxEggPlugin::OtherMessage1()
{
return _T("Modified by Ken Strickland");
}
/**
* Who knows?
*/
const TCHAR *MaxEggPlugin::OtherMessage2()
{
return _T("Who's got the funk? We do!");
}
/**
* Returns version * 100. defined in MAX_EGG_VERSION_NUMBER
*/
unsigned int MaxEggPlugin::Version()
{
return MAX_EGG_VERSION_NUMBER;
}
/**
* No about dialog box right now.
*/
void MaxEggPlugin::ShowAbout(HWND hWnd)
{
}
/**
* We'll support all options by default.
*/
BOOL MaxEggPlugin::SupportsOptions(int ext, DWORD options)
{
// According to the maxsdk help, there is only one option which is
// SCENE_EXPORT_SELECTED. This should return false until the code
// for converting only selected objects to egg is written
return false;
}
/*!
* This method creates and triggers the exporter. Basically it takes the
* user's options and builds a command-line parameter list from it.
* It then invokes the converter pretending it was invoked as a standalone
* program. BIG WARNING: The converter stuff often does exit() if the
* command line arguments are displeasing.
*/
int MaxEggPlugin::DoExport(const TCHAR *ptcOutputFilename,ExpInterface *ei,
Interface *pMaxInterface,
BOOL suppressPrompts, DWORD options)
{
MaxToEgg *pmteConverter = new MaxToEgg();
char *apcParameters[64];
char acOutputFilename[MAX_PATH];
int iParameterCount=0;
//Initialize our global error logger
Logger::globalLoggingInstance = new Logger( Logger::PIPE_TO_FILE,
"MaxEggLog.txt" );
//Set the various logging levels for the subsystems.
Logger::SetOneErrorMask( ME, Logger::SAT_ALL );
Logger::SetOneErrorMask( MTE, Logger::SAT_NULL_ERROR |
Logger::SAT_CRITICAL_ERROR |
Logger::SAT_PARAMETER_INVALID_ERROR |
Logger::SAT_OTHER_ERROR | Logger::SAT_HIGH_LEVEL );
Logger::SetOneErrorMask( MTEC, Logger::SAT_NULL_ERROR |
Logger::SAT_CRITICAL_ERROR |
Logger::SAT_PARAMETER_INVALID_ERROR |
Logger::SAT_OTHER_ERROR | Logger::SAT_HIGH_LEVEL |
Logger::SAT_MEDIUM_LEVEL | Logger::SAT_LOW_LEVEL |
Logger::SAT_DEBUG_SPAM_LEVEL );
Logger::SetOneErrorMask( MNEG, Logger::SAT_NULL_ERROR |
Logger::SAT_CRITICAL_ERROR |
Logger::SAT_PARAMETER_INVALID_ERROR |
Logger::SAT_OTHER_ERROR | Logger::SAT_HIGH_LEVEL |
Logger::SAT_MEDIUM_LEVEL | Logger::SAT_LOW_LEVEL );
Logger::SetOneErrorMask( MNEG_GEOMETRY_GENERATION, Logger::SAT_NULL_ERROR |
Logger::SAT_CRITICAL_ERROR |
Logger::SAT_PARAMETER_INVALID_ERROR |
Logger::SAT_OTHER_ERROR | Logger::SAT_HIGH_LEVEL |
Logger::SAT_MEDIUM_LEVEL | Logger::SAT_LOW_LEVEL );
Logger::SetOneErrorMask( LLOGGING, Logger::SAT_ALL );
Logger::FunctionEntry( "MaxEggPlugin::DoExport" );
// Copy the output filename so that it can be modified if necessary
strncpy(acOutputFilename,ptcOutputFilename,MAX_PATH-1);
acOutputFilename[MAX_PATH-1]=0;
// Panda reaaaaaaaaly wants the extension to be in lower case.
// So if we see a .egg at the end, lower case it.
if ((strlen(acOutputFilename)>4) &&
(stricmp(acOutputFilename+strlen(acOutputFilename)-4,".egg")==0)) {
strlwr(acOutputFilename+strlen(acOutputFilename)-4);
void MaxEggPlugin::AddEgg(MaxEggExpOptions *newEgg) {
if (numEggs >= maxEggs) {
MaxEggExpOptions **newList;
maxEggs *= 2;
newList = new MaxEggExpOptions*[maxEggs];
for (int i = 0; i < numEggs; i++) newList[i] = eggList[i];
delete [] eggList;
eggList = newList;
}
pmteConverter->SetMaxInterface(pMaxInterface);
// Set the command-line arguments
// ARGV[0] = program name
apcParameters[iParameterCount++]="MaxEggPlugin";
confirmExport = false;
if(!suppressPrompts)
// Displays the dialog box that retrieves the export options
DialogBoxParam(hInstance,
MAKEINTRESOURCE(IDD_PANEL),
pMaxInterface->GetMAXHWnd(),
MaxEggPluginOptionsDlgProc, (LPARAM)this);
// Stops the export if the user chooses to cancel
if (!confirmExport)
return true;
// ARGV[1] = Input file
// Use a bogus input filename that exists
apcParameters[iParameterCount++]="nul.max";
// ARGV[2,3] = Output file
// Pass in the output filename
// Output file has to be passed in with the -o parameter in order to be able
// to overwrite an existing file
apcParameters[iParameterCount++]="-o";
apcParameters[iParameterCount++]=acOutputFilename;
// ARGV[4,5] = Animation options (if animation is checked)
// Check if there is an animation to be saved and what type of animation it
// will be saved as. Then set the animation option.
if (animation) {
apcParameters[iParameterCount++]="-a";
switch (anim_type)
{
case AT_model:
apcParameters[iParameterCount++]="model";
break;
case AT_chan:
apcParameters[iParameterCount++]="chan";
break;
case AT_pose:
apcParameters[iParameterCount++]="pose";
break;
case AT_strobe:
apcParameters[iParameterCount++]="strobe";
break;
case AT_both:
apcParameters[iParameterCount++]="both";
break;
default:
apcParameters[iParameterCount++]="none";
break;
eggList[numEggs++] = newEgg;
}
void MaxEggPlugin::RemoveEgg(int i) {
if (i >= 0 && i < numEggs) {
delete eggList[i];
for (int j = i+1; j < numEggs;) eggList[i++] = eggList[j++];
--numEggs;
}
}
void MaxEggPlugin::BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev )
{
iObjParams = ip;
if ( !hMaxEggParams ) {
hMaxEggParams = ip->AddRollupPage(hInstance,
MAKEINTRESOURCE(IDD_PANEL),
MaxEggPluginOptionsDlgProc,
GetString(IDS_PARAMS),
(LPARAM)this );
ip->RegisterDlgWnd(hMaxEggParams);
} else {
SetWindowLongPtr( hMaxEggParams, GWLP_USERDATA, (LPARAM)this );
}
UpdateUI();
}
void MaxEggPlugin::EndEditParams( IObjParam *ip, ULONG flags,Animatable *prev)
{
SaveCheckState();
if ( flags&END_EDIT_REMOVEUI ) {
ip->UnRegisterDlgWnd(hMaxEggParams);
ip->DeleteRollupPage(hMaxEggParams);
hMaxEggParams = NULL;
} else {
SetWindowLongPtr( hMaxEggParams, GWLP_USERDATA, NULL );
}
iObjParams = NULL;
}
void MaxEggPlugin::SaveCheckState() {
if (!hMaxEggParams) return;
HWND lv = GetDlgItem(hMaxEggParams, IDC_LIST_EGGS);
for (int i = 0; i < numEggs; i++)
eggList[i]->checked = ListView_GetCheckState(lv, i);
}
void MaxEggPlugin::UpdateUI() {
HWND lv = GetDlgItem(hMaxEggParams, IDC_LIST_EGGS);
LV_COLUMN pCol;
if (ListView_GetColumnWidth(lv, 1) <= 0 || ListView_GetColumnWidth(lv, 1) > 10000) {
//Columns have not been setup, so initialize the control
ListView_SetExtendedListViewStyleEx(lv, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT,
LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
pCol.fmt = LVCFMT_LEFT;
pCol.cx = 96;
pCol.pszText = "Filename";
pCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
pCol.iSubItem = 0;
ListView_InsertColumn(lv, 0, &pCol);
pCol.cx = 44;
pCol.pszText = "Type";
ListView_InsertColumn(lv, 1, &pCol);
}
//Add the eggs to the list
ListView_DeleteAllItems(lv);
LV_ITEM Item;
Item.mask = LVIF_TEXT;
for (int i = 0; i < numEggs; i++) {
Item.iItem = i;
Item.iSubItem = 0;
Item.pszText = eggList[i]->shortName;
ListView_InsertItem(lv, &Item);
Item.iSubItem = 1;
switch(eggList[i]->anim_type) {
case MaxEggExpOptions::Anim_Type::AT_chan: Item.pszText = "Animation"; break;
case MaxEggExpOptions::Anim_Type::AT_both: Item.pszText = "Both"; break;
case MaxEggExpOptions::Anim_Type::AT_pose: Item.pszText = "Pose"; break;
case MaxEggExpOptions::Anim_Type::AT_model:
default: Item.pszText = "Model"; break;
}
ListView_SetItem(lv, &Item);
ListView_SetCheckState(lv, i, eggList[i]->checked);
}
// Set the "Overwrite Existing Files" and "Pview" checkboxes
CheckDlgButton(hMaxEggParams, IDC_OVERWRITE_CHECK,
autoOverwrite ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hMaxEggParams, IDC_PVIEW_CHECK,
pview ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hMaxEggParams, IDC_LOGGING,
logOutput ? BST_CHECKED : BST_UNCHECKED);
}
void MaxEggPlugin::DoExport() {
int good = 0, bad = 0;
char msg[2048];
strcpy(msg, "The following exports failed:\n");
SaveCheckState();
for (int i = 0; i < numEggs; i++) {
if (eggList[i]->checked) {
if (!eggList[i]->DoExport(iObjParams, autoOverwrite, logOutput)) {
++bad;
strcat(msg, eggList[i]->shortName);
strcat(msg, ".egg\n");
}
else ++good;
}
}
apcParameters[iParameterCount]=0;
// Parse the command line and run the converter
pmteConverter->parse_command_line(iParameterCount, apcParameters);
pmteConverter->Run();
bool bSuccessful = pmteConverter->IsSuccessful();
// Display a message box telling that the export is completed
if (bSuccessful)
MessageBox(pMaxInterface->GetMAXHWnd(),
"Export to EGG completed successfully.", "Panda3D Converter",
MB_OK);
if (bad == 0)
strcpy(msg, "All eggs exported successfully");
else
MessageBox(pMaxInterface->GetMAXHWnd(), "Export unsuccessful.",
"Panda3D Converter", MB_OK);
Logger::Log(MTEC, Logger::SAT_MEDIUM_LEVEL, "After finished mbox");
strcat(msg, "\nAll other eggs exported successfully");
// This was put in try block because originally deleting pmteConverter
// would throw an exception. That no longer happens, but this is still
// here for good measure
try {
Logger::Log(MTEC, Logger::SAT_MEDIUM_LEVEL, "before deleting pmteconverter");
delete pmteConverter;
} catch (...) {
Logger::Log(MTEC, Logger::SAT_MEDIUM_LEVEL, "before error message window");
MessageBox(pMaxInterface->GetMAXHWnd(), "I just got an unknown exception.",
"Panda3D Converter", MB_OK);
UINT mask = MB_OK;
if (bad > 0) mask |= MB_ICONEXCLAMATION;
else mask |= MB_ICONINFORMATION;
MessageBox(hMaxEggParams, msg, "Panda3D Export results", mask);
if (pview && good > 0) {
char pviewMsg[2048];
int pviewSkipped = 0;
strcpy(pviewMsg, "The following eggs were skipped since animations cannot be pviewed:\n");
for (i = 0; i < numEggs; i++)
if (eggList[i]->checked && eggList[i]->successful)
if (eggList[i]->anim_type != MaxEggExpOptions::AT_chan) {
char buf[1024];
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,0,sizeof(si));
si.cb= sizeof(si);
sprintf(buf, "Pview %s.egg?", eggList[i]->shortName);
if (MessageBox(hMaxEggParams, buf, "Panda3D exporter", MB_YESNO | MB_ICONQUESTION) == IDYES) {
char cmdLine[2048];
sprintf(cmdLine, "pview \"%s\"", eggList[i]->filename);
CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
NULL, NULL, &si, &pi);
}
}
else {
pviewSkipped++;
strcat(pviewMsg, eggList[i]->shortName);
strcat(pviewMsg, ".egg\n");
}
if (pviewSkipped > 0) {
strcat(pviewMsg, "\nExport animations using the \"both\" option to pview them.");
MessageBox(hMaxEggParams, pviewMsg, "Panda3D exporter", MB_OK | MB_ICONINFORMATION);
}
}
Logger::Log(MTEC, Logger::SAT_MEDIUM_LEVEL, "before logger function exit");
Logger::FunctionExit();
//Free the error logger
if ( Logger::globalLoggingInstance )
delete Logger::globalLoggingInstance;
return bSuccessful;
}
void MaxEggPlugin::BuildMesh()
{
int i;
if(meshBuilt) return;
mesh.setNumVerts(252);
mesh.setNumFaces(84);
mesh.setSmoothFlags(0);
mesh.setNumTVerts (0);
mesh.setNumTVFaces (0);
for (i=0; i<252; i++)
mesh.setVert(i, meshVerts[i][0]*10, meshVerts[i][1]*10, meshVerts[i][2]*10);
for (i=0; i<84; i++) {
mesh.faces[i].setEdgeVisFlags(1, 1, 0);
mesh.faces[i].setSmGroup(0);
mesh.faces[i].setVerts(i*3, i*3+1, i*3+2);
}
mesh.InvalidateGeomCache();
mesh.BuildStripsAndEdges();
meshBuilt = TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// The creation callback - sets the initial position of the helper in the scene.
///////////////////////////////////////////////////////////////////////////////////////////////////////
class MaxEggPluginCreateMouseCallBack: public CreateMouseCallBack
{
public:
int proc( ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat );
};
int MaxEggPluginCreateMouseCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat )
{
if (msg==MOUSE_POINT||msg==MOUSE_MOVE) {
switch(point) {
case 0:
mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
break;
case 1:
mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE));
if (msg==MOUSE_POINT) return CREATE_STOP;
break;
}
} else if (msg == MOUSE_ABORT) {
return CREATE_ABORT;
}
return CREATE_CONTINUE;
}
static MaxEggPluginCreateMouseCallBack MaxEggCreateMouseCB;
CreateMouseCallBack* MaxEggPlugin::GetCreateMouseCallBack()
{ return &MaxEggCreateMouseCB; }
///////////////////////////////////////////////////////////////////////////////////////////////////////
//Boilerplate functions for dealing with the display of the plugin
///////////////////////////////////////////////////////////////////////////////////////////////////////
void MaxEggPlugin::GetMat(TimeValue t, INode* inode, ViewExp* vpt, Matrix3& tm)
{
tm = inode->GetObjectTM(t);
tm.NoScale();
float scaleFactor = vpt->NonScalingObjectSize()*vpt->GetVPWorldWidth(tm.GetTrans())/(float)360.0;
tm.Scale(Point3(scaleFactor,scaleFactor,scaleFactor));
}
void MaxEggPlugin::GetDeformBBox(TimeValue t, Box3& box, Matrix3 *tm, BOOL useSel )
{
box = mesh.getBoundingBox(tm);
}
void MaxEggPlugin::GetLocalBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box )
{
Matrix3 m = inode->GetObjectTM(t);
Point3 pt;
Point3 q[4];
float scaleFactor = vpt->GetVPWorldWidth(m.GetTrans())/360.0f;
box = mesh.getBoundingBox();
box.Scale(scaleFactor);
}
void MaxEggPlugin::GetWorldBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box )
{
int i, nv; Matrix3 tm; Point3 pt;
GetMat(t,inode,vpt,tm);
nv = mesh.getNumVerts();
box.Init();
for (i=0; i<nv; i++)
box += tm*mesh.getVert(i);
}
int MaxEggPlugin::HitTest(TimeValue t, INode *inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt)
{
HitRegion hitRegion;
DWORD savedLimits;
Matrix3 m;
GraphicsWindow *gw = vpt->getGW();
Material *mtl = gw->getMaterial();
MakeHitRegion(hitRegion,type,crossing,4,p);
gw->setRndLimits(((savedLimits = gw->getRndLimits()) | GW_PICK) & ~GW_ILLUM);
GetMat(t,inode,vpt,m);
gw->setTransform(m);
gw->clearHitCode();
if (mesh.select( gw, mtl, &hitRegion, flags & HIT_ABORTONHIT ))
return TRUE;
return FALSE;
}
int MaxEggPlugin::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags)
{
Matrix3 m;
GraphicsWindow *gw = vpt->getGW();
Material *mtl = gw->getMaterial();
GetMat(t,inode,vpt,m);
gw->setTransform(m);
DWORD rlim = gw->getRndLimits();
gw->setRndLimits(GW_WIREFRAME|GW_BACKCULL);
if (inode->Selected())
gw->setColor( LINE_COLOR, GetSelColor());
else if(!inode->IsFrozen())
gw->setColor( LINE_COLOR, GetUIColor(COLOR_TAPE_OBJ));
mesh.render( gw, mtl, NULL, COMP_ALL);
return 0;
}
RefResult MaxEggPlugin::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message )
{
UpdateUI();
return REF_SUCCEED;
}
ObjectState MaxEggPlugin::Eval(TimeValue time)
{
return ObjectState(this);
}
Interval MaxEggPlugin::ObjectValidity(TimeValue t)
{
Interval ivalid;
ivalid.SetInfinite();
return ivalid;
}
RefTargetHandle MaxEggPlugin::Clone(RemapDir& remap)
{
MaxEggPlugin* newob = new MaxEggPlugin();
return(newob);
}
///////////////////////////////////////////////////////////
// Loading and saving the plugin
///////////////////////////////////////////////////////////
IOResult MaxEggPlugin::Save(ISave *isave) {
SaveCheckState();
for (int i = 0; i < numEggs; i++)
eggList[i]->Save(isave);
ChunkSave(isave, CHUNK_OVERWRITE_FLAG, autoOverwrite);
ChunkSave(isave, CHUNK_PVIEW_FLAG, pview);
ChunkSave(isave, CHUNK_LOG_OUTPUT, logOutput);
return IO_OK;
}
IOResult MaxEggPlugin::Load(ILoad *iload) {
IOResult res = iload->OpenChunk();
MaxEggExpOptions *temp;
while (res == IO_OK) {
switch(iload->CurChunkID()) {
case CHUNK_OVERWRITE_FLAG: autoOverwrite = ChunkLoadBool(iload); break;
case CHUNK_PVIEW_FLAG: pview = ChunkLoadBool(iload); break;
case CHUNK_LOG_OUTPUT: logOutput = ChunkLoadBool(iload); break;
case CHUNK_EGG_EXP_OPTIONS:
temp = new MaxEggExpOptions();
temp->Load(iload);
AddEgg(temp);
break;
}
iload->CloseChunk();
res = iload->OpenChunk();
}
return IO_OK;
}

View File

@ -19,12 +19,14 @@
//Includes & Definitions
#include "MaxToEgg.h"
#include "MaxEggExpOptions.h"
#include "windef.h"
/* Error-Reporting Includes
*/
#include "Logger.h"
#define ME Logger::ST_MAP_ME_TO_APP_SPECIFIC_SYSTEM6
#define MaxEggPlugin_CLASS_ID Class_ID(0x7ac0d6b7, 0x55731ef6)
/* Externed Globals
*/
@ -42,51 +44,333 @@ extern TCHAR *GetString(int id);
a suitable interface to Max files can be connected from a standalone
program instead of a plugin.
*/
class MaxEggPlugin : public SceneExport
class MaxEggPlugin : public HelperObject
{
public:
static HWND hParams;
bool confirmExport;
bool makeBam;
bool animation;
enum Anim_Type {
AT_none,
AT_model,
AT_chan,
AT_pose,
AT_strobe,
AT_both
};
Anim_Type anim_type;
// Number of extensions supported
int ExtCount();
// Extension #n (i.e. "3DS")
const TCHAR *Ext(int n);
// Long ASCII description (i.e. "Autodesk 3D Studio File")
const TCHAR *LongDesc();
// Short ASCII description (i.e. "3D Studio")
const TCHAR *ShortDesc();
// ASCII Author name
const TCHAR *AuthorName();
// ASCII Copyright message
const TCHAR *CopyrightMessage();
// Other message #1
const TCHAR *OtherMessage1();
// Other message #2
const TCHAR *OtherMessage2();
// Version number * 100 (i.e. v3.01 = 301)
unsigned int Version();
// Show DLL's "About..." box
void ShowAbout(HWND hWnd);
MaxEggExpOptions **eggList;
int numEggs;
int maxEggs;
BOOL SupportsOptions(int ext, DWORD options);
int DoExport(const TCHAR *name,ExpInterface *ei,
Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0);
public:
bool autoOverwrite;
bool pview;
bool logOutput;
// Class vars
static Mesh mesh; // This plugin generates no geometry, this mesh is not passed on to 3D Studio.
static short meshBuilt;
static HWND hMaxEggParams;
static IObjParam *iObjParams;
//Constructor/Destructor
MaxEggPlugin();
virtual ~MaxEggPlugin();
//Other class Methods
void DoExport();
void UpdateUI();
void SaveCheckState();
void BuildMesh();
void AddEgg(MaxEggExpOptions *newEgg);
void RemoveEgg(int i);
MaxEggExpOptions *GetEgg(int i) { return (i >= 0 && i < numEggs) ? eggList[i] : NULL; }
// Required implimented virtual methods:
// inherited virtual methods for Reference-management
RefResult NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message );
void GetMat(TimeValue t, INode* inod, ViewExp *vpt, Matrix3& mat);
// From BaseObject
int HitTest(TimeValue t, INode* inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt);
int Display(TimeValue t, INode* inode, ViewExp *vpt, int flags);
CreateMouseCallBack* GetCreateMouseCallBack();
void BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev);
void EndEditParams( IObjParam *ip, ULONG flags,Animatable *next);
TCHAR *GetObjectName() { return GetString(IDS_LIBDESCRIPTION); }
// From Object
ObjectState Eval(TimeValue time);
void InitNodeName(TSTR& s) { s = GetString(IDS_CLASS_NAME); }
Interval ObjectValidity(TimeValue time);
void Invalidate();
int DoOwnSelectHilite() { return 1; }
// From GeomObject
int IntersectRay(TimeValue t, Ray& r, float& at) { return 0; }
void GetWorldBoundBox(TimeValue t, INode *mat, ViewExp *vpt, Box3& box );
void GetLocalBoundBox(TimeValue t, INode *mat, ViewExp *vpt, Box3& box );
void GetDeformBBox(TimeValue t, Box3& box, Matrix3 *tm, BOOL useSel );
// Animatable methods
void DeleteThis() { delete this; }
Class_ID ClassID() { return MaxEggPlugin_CLASS_ID; }
void GetClassName(TSTR& s) { s = TSTR(GetString(IDS_CLASS_NAME)); }
TSTR SubAnimName(int i) { return TSTR(GetString(IDS_CLASS_NAME)); }
// From ref
RefTargetHandle Clone(RemapDir& remap = NoRemap());
// IO
IOResult Save(ISave *isave);
IOResult Load(ILoad *iload);
};
const double meshVerts[252][3] = {
{0.729464, 0.714986, -0.919852},
{0.466137, 0.160201, -0.594656},
{-0.265897, 0.714986, -1.14704},
{0.466137, 0.160201, -0.594656},
{-0.177333, 0.160201, -0.741523},
{-0.265897, 0.714986, -1.14704},
{-0.265897, 0.714986, -1.14704},
{-0.177333, 0.160201, -0.741523},
{-1.06411, 0.714986, -0.510479},
{-0.177333, 0.160201, -0.741523},
{-0.693356, 0.160201, -0.330009},
{-1.06411, 0.714986, -0.510479},
{-1.06411, 0.714986, 0.510479},
{-1.06411, 0.714986, -0.510479},
{-0.693356, 0.160201, 0.330009},
{-0.693356, 0.160201, -0.330009},
{-0.693356, 0.160201, 0.330009},
{-1.06411, 0.714986, -0.510479},
{-0.265897, 0.714986, 1.14704},
{-1.06411, 0.714986, 0.510479},
{-0.177333, 0.160201, 0.741523},
{-0.693356, 0.160201, 0.330009},
{-0.177333, 0.160201, 0.741523},
{-1.06411, 0.714986, 0.510479},
{0.729464, 0.714986, 0.919852},
{-0.265897, 0.714986, 1.14704},
{0.466137, 0.160201, 0.594656},
{-0.177333, 0.160201, 0.741523},
{0.466137, 0.160201, 0.594656},
{-0.265897, 0.714986, 1.14704},
{1.17244, 0.714986, 0.0},
{0.729464, 0.714986, 0.919852},
{0.752508, 0.160201, 0.0},
{0.466137, 0.160201, 0.594656},
{0.752508, 0.160201, 0.0},
{0.729464, 0.714986, 0.919852},
{0.729464, 0.714986, -0.919852},
{1.17244, 0.714986, 0.0},
{0.466137, 0.160201, -0.594656},
{0.752508, 0.160201, 0.0},
{0.466137, 0.160201, -0.594656},
{1.17244, 0.714986, 0.0},
{-0.286334, 1.44995, -1.26822},
{0.814187, 1.44995, -1.01703},
{-0.265897, 0.714986, -1.14704},
{0.729464, 0.714986, -0.919852},
{-0.265897, 0.714986, -1.14704},
{0.814187, 1.44995, -1.01703},
{-1.16888, 1.44995, -0.564412},
{-0.286334, 1.44995, -1.26822},
{-1.06411, 0.714986, -0.510479},
{-0.265897, 0.714986, -1.14704},
{-1.06411, 0.714986, -0.510479},
{-0.286334, 1.44995, -1.26822},
{-1.16888, 1.44995, 0.564411},
{-1.16888, 1.44995, -0.564412},
{-1.06411, 0.714986, 0.510479},
{-1.06411, 0.714986, -0.510479},
{-1.06411, 0.714986, 0.510479},
{-1.16888, 1.44995, -0.564412},
{-1.16888, 1.44995, 0.564411},
{-1.06411, 0.714986, 0.510479},
{-0.286334, 1.44995, 1.26822},
{-1.06411, 0.714986, 0.510479},
{-0.265897, 0.714986, 1.14704},
{-0.286334, 1.44995, 1.26822},
{-0.286334, 1.44995, 1.26822},
{-0.265897, 0.714986, 1.14704},
{0.814187, 1.44995, 1.01703},
{-0.265897, 0.714986, 1.14704},
{0.729464, 0.714986, 0.919852},
{0.814187, 1.44995, 1.01703},
{1.30396, 1.44995, 0.0},
{0.814187, 1.44995, 1.01703},
{1.17244, 0.714986, 0.0},
{0.729464, 0.714986, 0.919852},
{1.17244, 0.714986, 0.0},
{0.814187, 1.44995, 1.01703},
{1.30396, 1.44995, 0.0},
{1.17244, 0.714986, 0.0},
{0.814187, 1.44995, -1.01703},
{1.17244, 0.714986, 0.0},
{0.729464, 0.714986, -0.919852},
{0.814187, 1.44995, -1.01703},
{-0.286334, 1.44995, -1.26822},
{-0.227573, 2.16723, -1.05763},
{0.814187, 1.44995, -1.01703},
{0.814187, 1.44995, -1.01703},
{-0.227573, 2.16723, -1.05763},
{0.690208, 2.16723, -0.848157},
{-1.16888, 1.44995, -0.564412},
{-0.963577, 2.16723, -0.470692},
{-0.286334, 1.44995, -1.26822},
{-0.286334, 1.44995, -1.26822},
{-0.963577, 2.16723, -0.470692},
{-0.227573, 2.16723, -1.05763},
{-1.16888, 1.44995, -0.564412},
{-1.16888, 1.44995, 0.564411},
{-0.963577, 2.16723, -0.470692},
{-1.16888, 1.44995, 0.564411},
{-0.963577, 2.16723, 0.470692},
{-0.963577, 2.16723, -0.470692},
{-1.16888, 1.44995, 0.564411},
{-0.286334, 1.44995, 1.26822},
{-0.963577, 2.16723, 0.470692},
{-0.286334, 1.44995, 1.26822},
{-0.227574, 2.16723, 1.05763},
{-0.963577, 2.16723, 0.470692},
{-0.286334, 1.44995, 1.26822},
{0.814187, 1.44995, 1.01703},
{-0.227574, 2.16723, 1.05763},
{0.814187, 1.44995, 1.01703},
{0.690208, 2.16723, 0.848157},
{-0.227574, 2.16723, 1.05763},
{0.814187, 1.44995, 1.01703},
{1.30396, 1.44995, 0.0},
{0.690208, 2.16723, 0.848157},
{1.30396, 1.44995, 0.0},
{1.09866, 2.16723, 0.0},
{0.690208, 2.16723, 0.848157},
{0.814187, 1.44995, -1.01703},
{0.690208, 2.16723, -0.848157},
{1.30396, 1.44995, 0.0},
{1.30396, 1.44995, 0.0},
{0.690208, 2.16723, -0.848157},
{1.09866, 2.16723, 0.0},
{-0.227573, 2.16723, -1.05763},
{-0.154893, 2.72566, -0.759032},
{0.690208, 2.16723, -0.848157},
{0.690208, 2.16723, -0.848157},
{-0.154893, 2.72566, -0.759032},
{0.50377, 2.72566, -0.608696},
{-0.963577, 2.16723, -0.470692},
{-0.683099, 2.72566, -0.337801},
{-0.227573, 2.16723, -1.05763},
{-0.227573, 2.16723, -1.05763},
{-0.683099, 2.72566, -0.337801},
{-0.154893, 2.72566, -0.759032},
{-0.963577, 2.16723, -0.470692},
{-0.963577, 2.16723, 0.470692},
{-0.683099, 2.72566, -0.337801},
{-0.963577, 2.16723, 0.470692},
{-0.683099, 2.72566, 0.337801},
{-0.683099, 2.72566, -0.337801},
{-0.963577, 2.16723, 0.470692},
{-0.227574, 2.16723, 1.05763},
{-0.683099, 2.72566, 0.337801},
{-0.227574, 2.16723, 1.05763},
{-0.154893, 2.72566, 0.759032},
{-0.683099, 2.72566, 0.337801},
{-0.227574, 2.16723, 1.05763},
{0.690208, 2.16723, 0.848157},
{-0.154893, 2.72566, 0.759032},
{0.690208, 2.16723, 0.848157},
{0.50377, 2.72566, 0.608696},
{-0.154893, 2.72566, 0.759032},
{0.690208, 2.16723, 0.848157},
{1.09866, 2.16723, 0.0},
{0.50377, 2.72566, 0.608696},
{1.09866, 2.16723, 0.0},
{0.796903, 2.72566, 0.0},
{0.50377, 2.72566, 0.608696},
{1.09866, 2.16723, 0.0},
{0.690208, 2.16723, -0.848157},
{0.796903, 2.72566, 0.0},
{0.690208, 2.16723, -0.848157},
{0.50377, 2.72566, -0.608696},
{0.796903, 2.72566, 0.0},
{0.50377, 2.72566, -0.608696},
{-0.154893, 2.72566, -0.759032},
{0.259722, 3.11175, -0.299638},
{-0.154893, 2.72566, -0.759032},
{-0.0645132, 3.11175, -0.373643},
{0.259722, 3.11175, -0.299638},
{-0.154893, 2.72566, -0.759032},
{-0.683099, 2.72566, -0.337801},
{-0.0645132, 3.11175, -0.373643},
{-0.683099, 2.72566, -0.337801},
{-0.324529, 3.11175, -0.166287},
{-0.0645132, 3.11175, -0.373643},
{-0.683099, 2.72566, -0.337801},
{-0.683099, 2.72566, 0.337801},
{-0.324529, 3.11175, -0.166287},
{-0.683099, 2.72566, 0.337801},
{-0.324529, 3.11175, 0.166287},
{-0.324529, 3.11175, -0.166287},
{-0.683099, 2.72566, 0.337801},
{-0.154893, 2.72566, 0.759032},
{-0.324529, 3.11175, 0.166287},
{-0.154893, 2.72566, 0.759032},
{-0.0645132, 3.11175, 0.373642},
{-0.324529, 3.11175, 0.166287},
{-0.154893, 2.72566, 0.759032},
{0.50377, 2.72566, 0.608696},
{-0.0645132, 3.11175, 0.373642},
{0.50377, 2.72566, 0.608696},
{0.259722, 3.11175, 0.299638},
{-0.0645132, 3.11175, 0.373642},
{0.50377, 2.72566, 0.608696},
{0.796903, 2.72566, 0.0},
{0.259722, 3.11175, 0.299638},
{0.796903, 2.72566, 0.0},
{0.40402, 3.11175, 0.0},
{0.259722, 3.11175, 0.299638},
{0.796903, 2.72566, 0.0},
{0.50377, 2.72566, -0.608696},
{0.40402, 3.11175, 0.0},
{0.50377, 2.72566, -0.608696},
{0.259722, 3.11175, -0.299638},
{0.40402, 3.11175, 0.0},
{-0.177333, 0.160201, -0.741523},
{0.466137, 0.160201, -0.594656},
{-0.00334214, 0.00443203, 0.0},
{-0.693356, 0.160201, -0.330009},
{-0.177333, 0.160201, -0.741523},
{-0.00334214, 0.00443203, 0.0},
{-0.693356, 0.160201, 0.330009},
{-0.693356, 0.160201, -0.330009},
{-0.00334214, 0.00443203, 0.0},
{-0.177333, 0.160201, 0.741523},
{-0.693356, 0.160201, 0.330009},
{-0.00334214, 0.00443203, 0.0},
{0.466137, 0.160201, 0.594656},
{-0.177333, 0.160201, 0.741523},
{-0.00334214, 0.00443203, 0.0},
{0.752508, 0.160201, 0.0},
{0.466137, 0.160201, 0.594656},
{-0.00334214, 0.00443203, 0.0},
{0.466137, 0.160201, -0.594656},
{0.752508, 0.160201, 0.0},
{-0.00334214, 0.00443203, 0.0},
{0.259722, 3.11175, -0.299638},
{-0.0645132, 3.11175, -0.373643},
{0.0207683, 3.20912, 0.0},
{-0.0645132, 3.11175, -0.373643},
{-0.324529, 3.11175, -0.166287},
{0.0207683, 3.20912, 0.0},
{-0.324529, 3.11175, -0.166287},
{-0.324529, 3.11175, 0.166287},
{0.0207683, 3.20912, 0.0},
{-0.324529, 3.11175, 0.166287},
{-0.0645132, 3.11175, 0.373642},
{0.0207683, 3.20912, 0.0},
{-0.0645132, 3.11175, 0.373642},
{0.259722, 3.11175, 0.299638},
{0.0207683, 3.20912, 0.0},
{0.259722, 3.11175, 0.299638},
{0.40402, 3.11175, 0.0},
{0.0207683, 3.20912, 0.0},
{0.40402, 3.11175, 0.0},
{0.259722, 3.11175, -0.299638},
{0.0207683, 3.20912, 0.0}
};
#endif // __MaxEggPlugin__H

View File

@ -1,180 +1,219 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PANEL DIALOGEX 0, 0, 374, 169
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION |
WS_SYSMENU
EXSTYLE WS_EX_TOOLWINDOW
FONT 8, "MS Sans Serif", 0, 0, 0x1
BEGIN
CTEXT "MaxToEgg Exporter",IDC_STATIC,7,7,360,10
CTEXT "By Corey Revilla, Ken Strickland, and Steve Osman.",
IDC_STATIC,7,21,360,19
CONTROL "Also create .BAM file",IDC_MAKE_BAM,"Button",
BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,35,138,81,10
PUSHBUTTON "Done",IDC_DONE,303,139,50,14
GROUPBOX "",IDC_STATIC,21,38,333,93
CONTROL "Animation",IDC_ANIMATION,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,27,38,49,10
CONTROL "model only",IDC_MODEL,"Button",BS_AUTORADIOBUTTON |
WS_DISABLED | WS_GROUP | WS_TABSTOP,35,51,60,12
CONTROL "animation channel only",IDC_CHAN,"Button",
BS_AUTORADIOBUTTON | WS_DISABLED | WS_TABSTOP,35,65,92,
12
CONTROL "pose",IDC_POSE,"Button",BS_AUTORADIOBUTTON |
WS_DISABLED | WS_TABSTOP,35,80,60,12
CONTROL "strobe",IDC_STROBE,"Button",BS_AUTORADIOBUTTON |
WS_DISABLED | WS_TABSTOP,35,95,60,12
CONTROL "model and animation channel",IDC_BOTH,"Button",
BS_AUTORADIOBUTTON | WS_DISABLED | WS_TABSTOP,35,110,110,
12
EDITTEXT IDC_CN,254,54,71,12,ES_AUTOHSCROLL | WS_DISABLED
EDITTEXT IDC_SF,303,70,22,12,ES_AUTOHSCROLL | WS_DISABLED
EDITTEXT IDC_IF,303,103,22,12,ES_AUTOHSCROLL | WS_DISABLED
EDITTEXT IDC_EF,303,87,22,12,ES_AUTOHSCROLL | WS_DISABLED
LTEXT "Character Name",IDC_CN_LABEL,187,56,54,10,WS_DISABLED
LTEXT "Start Frame",IDC_SF_LABEL,187,72,48,10,WS_DISABLED
LTEXT "End Frame",IDC_EF_LABEL,187,88,45,10,WS_DISABLED
LTEXT "Frame Increment",IDC_IF_LABEL,187,105,64,10,WS_DISABLED
PUSHBUTTON "Cancel",IDC_CANCEL,250,139,50,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PANEL, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 367
TOPMARGIN, 7
BOTTOMMARGIN, 162
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,0,0,0
PRODUCTVERSION 3,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileVersion", "4.0.0.0"
VALUE "InternalName", "MaxEgg"
// VALUE "OriginalFilename", "MaxEgg.dle"
VALUE "ProductName", "3ds max"
VALUE "ProductVersion", "4.0.0.0"
VALUE "FileDescription", "Panda3D .egg exporter"
VALUE "Comments", "TECH: "
VALUE "LegalTrademarks", "3D Studio MAX, Biped, Character Studio, Heidi, Kinetix and Physique are registered trademarks and 3ds max, combustion, Discreet, DWG Unplugged, DXF, FLI and FLC are trademarks of Autodesk, Inc."
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_LIBDESCRIPTION "Panda3D .egg exporter"
IDS_CATEGORY "egg"
IDS_CLASS_NAME "MaxEgg"
IDS_PARAMS "Parameters"
IDS_SPIN "Spin"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PANEL DIALOGEX 0, 0, 109, 192
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif", 0, 0, 0x1
BEGIN
CTEXT "Panda 3D EGG Exporter",IDC_PANEL_TITLE,6,6,96,11,
WS_BORDER
LTEXT "Eggs",IDC_EGGS_LABEL,6,19,62,8
CONTROL "Custom1",IDC_LIST_EGGS,"SysListView32",LVS_REPORT |
LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER |
WS_TABSTOP,6,28,96,69,WS_EX_CLIENTEDGE
CONTROL "Add...",IDC_ADD_EGG,"CustButton",WS_TABSTOP,6,102,24,12
CONTROL "Edit...",IDC_EDIT_EGG,"CustButton",WS_TABSTOP,36,102,30,
12
CONTROL "Remove",IDC_REMOVE_EGG,"CustButton",WS_TABSTOP,72,102,
30,12
CONTROL "Overwrite Existing Files",IDC_OVERWRITE_CHECK,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,6,126,103,8,
WS_EX_TRANSPARENT
CONTROL "Export Now",IDC_EXPORT,"CustButton",WS_TABSTOP,5,164,96,
18
CONTROL "Pview Output",IDC_PVIEW_CHECK,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,6,138,103,8,WS_EX_TRANSPARENT
CONTROL "Log Output",IDC_LOGGING,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,6,148,90,11
END
IDD_EGG_DETAILS DIALOGEX 0, 0, 256, 169
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "Export Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Export Type:",IDC_STATIC,6,5,54,8
CONTROL "Model",IDC_MODEL,"Button",BS_AUTORADIOBUTTON,54,4,38,12
CONTROL "Animation",IDC_ANIMATION,"Button",BS_AUTORADIOBUTTON,96,
4,50,12
CONTROL "Both",IDC_BOTH,"Button",BS_AUTORADIOBUTTON,150,4,35,12
CONTROL "Pose",IDC_POSE,"Button",BS_AUTORADIOBUTTON,186,4,36,12
GROUPBOX "Options",IDC_STATIC,6,18,246,126,WS_GROUP
LTEXT "Filename",IDC_STATIC,12,30,66,8
CONTROL "Custom1",IDC_FILENAME,"CustEdit",WS_TABSTOP,12,42,180,
12
CONTROL "Browse...",IDC_BROWSE,"CustButton",WS_TABSTOP,198,42,48,
12
CONTROL "Export Entire Scene",IDC_EXPORT_ALL,"Button",
BS_AUTORADIOBUTTON | WS_GROUP,12,60,114,8
CONTROL "Export Meshes:",IDC_EXPORT_SELECTED,"Button",
BS_AUTORADIOBUTTON,12,71,114,8
LISTBOX IDC_LIST_EXPORT,12,84,114,36,LBS_SORT |
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
WS_TABSTOP
CONTROL "Add...",IDC_ADD_EXPORT,"CustButton",WS_TABSTOP,12,126,
54,12
CONTROL "Remove...",IDC_REMOVE_EXPORT,"CustButton",WS_TABSTOP,72,
126,54,12
CONTROL "Export All Frames",IDC_EXP_ALL_FRAMES,"Button",
BS_AUTORADIOBUTTON | WS_GROUP,144,60,96,8
CONTROL "Use Range:",IDC_EXP_SEL_FRAMES,"Button",
BS_AUTORADIOBUTTON | BS_VCENTER,144,70,102,11
LTEXT "Start Frame",IDC_SF_LABEL,144,86,42,8,WS_DISABLED
CONTROL "Custom4",IDC_SF,"CustEdit",WS_DISABLED | WS_TABSTOP,186,
84,48,12
LTEXT "End Frame",IDC_EF_LABEL,144,103,42,8,WS_DISABLED
CONTROL "Custom5",IDC_EF,"CustEdit",WS_DISABLED | WS_TABSTOP,186,
101,48,12
CONTROL "Double-sided Polygons",IDC_CHECK1,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,144,126,102,12
CONTROL "OK",IDC_OK,"CustButton",WS_TABSTOP,162,150,42,12
CONTROL "Cancel",IDC_CANCEL,"CustButton",WS_TABSTOP,210,150,42,
12
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PANEL, DIALOG
BEGIN
BOTTOMMARGIN, 182
END
IDD_EGG_DETAILS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 249
TOPMARGIN, 7
BOTTOMMARGIN, 162
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,0,0,0
PRODUCTVERSION 3,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileVersion", "4.0.0.0"
VALUE "InternalName", "MaxEgg"
VALUE "OriginalFilename", "MaxEgg.dle"
VALUE "ProductName", "3ds max"
VALUE "ProductVersion", "4.0.0.0"
VALUE "FileDescription", "Panda3D .egg exporter"
VALUE "Comments", "TECH: "
VALUE "LegalTrademarks", "3D Studio MAX, Biped, Character Studio, Heidi, Kinetix and Physique are registered trademarks and 3ds max, combustion, Discreet, DWG Unplugged, DXF, FLI and FLC are trademarks of Autodesk, Inc."
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_LIBDESCRIPTION "Panda3D .egg exporter"
IDS_CATEGORY "Exporters"
IDS_CLASS_NAME "Panda3D"
IDS_PARAMS "Parameters"
IDS_SPIN "Spin"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,768 @@
/*
MaxEgg.cpp
Created by Phillip Saltzman, 2/15/05
Carnegie Mellon University, Entetainment Technology Center
This file implements the classes that are used to choose
what to export from 3D Studio max
*/
#include "MaxEggExpOptions.h"
//Disable the forcing int to true or false performance warning
#pragma warning(disable: 4800)
void SetICustEdit(HWND wnd, int nIDDlgItem, char *text)
{
ICustEdit *edit = GetICustEdit(GetDlgItem(wnd, nIDDlgItem));
edit->SetText(text);
ReleaseICustEdit(edit);
}
void SetICustEdit(HWND wnd, int nIDDlgItem, int n)
{
char text[80];
sprintf(text, "%d", n);
ICustEdit *edit = GetICustEdit(GetDlgItem(wnd, nIDDlgItem));
edit->SetText(text);
ReleaseICustEdit(edit);
}
char *GetICustEditT(HWND wnd)
{
static char buffer[2084];
ICustEdit *edit = GetICustEdit(wnd);
edit->GetText(buffer,2084);
ReleaseICustEdit(edit);
return buffer;
}
int GetICustEditI(HWND wnd, BOOL *valid)
{
ICustEdit *edit = GetICustEdit(wnd);
int i = edit->GetInt(valid);
ReleaseICustEdit(edit);
return i;
}
void ChunkSave(ISave *isave, int chunkid, int value)
{
ULONG nb;
isave->BeginChunk(chunkid);
isave->Write(&value, sizeof(int), &nb);
isave->EndChunk();
}
void ChunkSave(ISave *isave, int chunkid, ULONG value)
{
ULONG nb;
isave->BeginChunk(chunkid);
isave->Write(&value, sizeof(ULONG), &nb);
isave->EndChunk();
}
void ChunkSave(ISave *isave, int chunkid, bool value)
{
ULONG nb;
isave->BeginChunk(chunkid);
isave->Write(&value, sizeof(bool), &nb);
isave->EndChunk();
}
void ChunkSave(ISave *isave, int chunkid, char *value)
{
ULONG nb;
isave->BeginChunk(chunkid);
int bytes = strlen(value) + 1;
isave->Write(&bytes, sizeof(int), &nb);
isave->Write(value, bytes, &nb);
isave->EndChunk();
}
char *ChunkLoadString(ILoad *iload, char *buffer, int maxBytes)
{
ULONG nb;
int bytes;
IOResult res;
res = iload->Read(&bytes, sizeof(int), &nb);
assert(res == IO_OK && bytes <= maxBytes);
res = iload->Read(buffer, bytes, &nb);
assert(res == IO_OK);
return buffer;
}
int ChunkLoadInt(ILoad *iload)
{
ULONG nb;
int value;
IOResult res;
res = iload->Read(&value, sizeof(int), &nb);
assert(res == IO_OK);
return value;
}
int ChunkLoadULONG(ILoad *iload)
{
ULONG nb, value;
IOResult res;
res = iload->Read(&value, sizeof(ULONG), &nb);
assert(res == IO_OK);
return value;
}
bool ChunkLoadBool(ILoad *iload)
{
ULONG nb;
bool value;
IOResult res;
res = iload->Read(&value, sizeof(bool), &nb);
assert(res == IO_OK);
return value;
}
void showAnimControls(HWND hWnd, BOOL val) {
ShowWindow(GetDlgItem(hWnd, IDC_EF_LABEL), val);
ShowWindow(GetDlgItem(hWnd, IDC_EF), val);
ShowWindow(GetDlgItem(hWnd, IDC_SF_LABEL), val);
SetWindowText(GetDlgItem(hWnd, IDC_EXP_SEL_FRAMES),
val ? "Use Range:" : "Use Frame:");
}
void enableAnimControls(HWND hWnd, BOOL val) {
EnableWindow(GetDlgItem(hWnd, IDC_SF_LABEL), val);
EnableWindow(GetDlgItem(hWnd, IDC_SF), val);
EnableWindow(GetDlgItem(hWnd, IDC_EF_LABEL), val);
EnableWindow(GetDlgItem(hWnd, IDC_EF), val);
}
void enableChooserControls(HWND hWnd, BOOL val) {
EnableWindow(GetDlgItem(hWnd, IDC_LIST_EXPORT), val);
EnableWindow(GetDlgItem(hWnd, IDC_ADD_EXPORT), val);
EnableWindow(GetDlgItem(hWnd, IDC_REMOVE_EXPORT), val);
}
#define ANIM_RAD_NONE 0
#define ANIM_RAD_EXPALL 1
#define ANIM_RAD_EXPSEL 2
#define ANIM_RAD_ALL 3
void enableAnimRadios(HWND hWnd, int mask) {
EnableWindow(GetDlgItem(hWnd, IDC_EXP_ALL_FRAMES), mask & ANIM_RAD_EXPALL);
EnableWindow(GetDlgItem(hWnd, IDC_EXP_SEL_FRAMES), mask & ANIM_RAD_EXPSEL);
}
// Handles the work of actually picking the target.
class AddNodeCB : public HitByNameDlgCallback
{
public:
MaxEggExpOptions *ph; //Pointer to the parent class
HWND hWnd; //Handle to the parent dialog
AddNodeCB (MaxEggExpOptions *instance, HWND wnd) :
ph(instance), hWnd(wnd) {}
virtual TCHAR *dialogTitle() {return _T("Objects to Export");}
virtual TCHAR *buttonText() {return _T("Select");}
virtual int filter(INode *node);
virtual void proc(INodeTab &nodeTab);
};
//This tells what should be in the list
//Allow only triangular objects, nurbs, and joints
int AddNodeCB::filter(INode *node) {
if (!node) return 0;
Object *obj = node->EvalWorldState(0).obj;
Control *c = node->GetTMController();
NURBSSet getSet;
bool is_bone = (node->GetBoneNodeOnOff() || //True for bones
(c && //True for bipeds
((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) ||
(c->ClassID() == BIPBODY_CONTROL_CLASS_ID) ||
(c->ClassID() == FOOTPRINT_CLASS_ID))));
if (IsDlgButtonChecked(hWnd, IDC_ANIMATION) == BST_CHECKED)
return is_bone && !ph->FindNode(node->GetHandle());
else
return (
!is_bone &&
((obj->SuperClassID() == GEOMOBJECT_CLASS_ID && //Allow geometrics
obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) ||
(obj->SuperClassID() == SHAPE_CLASS_ID && //Allow CV NURBS
obj->ClassID() == EDITABLE_SURF_CLASS_ID &&
GetNURBSSet(obj, 0, getSet, TRUE) &&
getSet.GetNURBSObject(0)->GetType() == kNCVCurve)) &&
!ph->FindNode(node->GetHandle())); //Only allow items not already selected
}
//Adds all of the selected items to the list
void AddNodeCB::proc(INodeTab &nodeTab) {
for (int i = 0; i < nodeTab.Count(); i++)
ph->AddNode(nodeTab[i]->GetHandle());
ph->RefreshNodeList(hWnd);
}
//This callback class generates a list of nodes that have previously been selected
class RemoveNodeCB : public HitByNameDlgCallback
{
public:
MaxEggExpOptions *ph; //Pointer to the parent class
HWND hWnd; //Handle to the parent dialog
RemoveNodeCB (MaxEggExpOptions *instance, HWND wnd) :
ph(instance), hWnd(wnd) {}
virtual TCHAR *dialogTitle() {return _T("Objects to Remove");}
virtual TCHAR *buttonText() {return _T("Remove");}
virtual int filter(INode *node) {return (node && ph->FindNode(node->GetHandle()));}
virtual void proc(INodeTab &nodeTab);
};
//Adds all of the selected items to the list
void RemoveNodeCB::proc(INodeTab &nodeTab) {
for (int i = 0; i < nodeTab.Count(); i++)
ph->RemoveNodeByHandle(nodeTab[i]->GetHandle());
ph->RefreshNodeList(hWnd);
}
MaxEggExpOptions::MaxEggExpOptions () :
checked(true), anim_type(AT_model), sf(INT_MIN), ef(INT_MIN),
expWholeScene(true), dblSided(false), numNodes(0), maxNodes(5),
choosingNodes(false), prev_type(AT_model) {
*filename = NULL;
nodeList = new ULONG[maxNodes];
}
BOOL CALLBACK MaxEggExpOptionsProc( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
char tempFilename[2048];
//We pass in our plugin through the lParam variable. Let's convert it back.
MaxEggExpOptions *imp = (MaxEggExpOptions*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
if ( !imp && message != WM_INITDIALOG ) return FALSE;
switch(message)
{
// When we start, center the window.
case WM_INITDIALOG:
// this line is very necessary to pass the plugin as the lParam
SetWindowLongPtr(hWnd,GWLP_USERDATA,lParam);
((MaxEggExpOptions*)lParam)->UpdateUI(hWnd);
return TRUE; break;
case WM_CLOSE:
EndDialog(hWnd, FALSE);
return TRUE; break;
// A control was modified
case WM_COMMAND:
//The modified control is found in the lower word of the wParam long.
switch( LOWORD(wParam) ) {
case IDC_MODEL:
if (HIWORD(wParam) == BN_CLICKED) {
SetWindowText(GetDlgItem(hWnd, IDC_EXPORT_SELECTED),
"Export Meshes:");
enableAnimRadios(hWnd, ANIM_RAD_NONE);
showAnimControls(hWnd, TRUE);
enableAnimControls(hWnd, FALSE);
if (imp->prev_type == MaxEggExpOptions::AT_chan) imp->ClearNodeList(hWnd);
imp->prev_type = MaxEggExpOptions::AT_model;
return TRUE;
}
break;
case IDC_ANIMATION:
if (HIWORD(wParam) == BN_CLICKED) {
SetWindowText(GetDlgItem(hWnd, IDC_EXPORT_SELECTED),
"Export Bones:");
enableAnimRadios(hWnd, ANIM_RAD_ALL);
showAnimControls(hWnd, TRUE);
enableAnimControls(hWnd, IsDlgButtonChecked(hWnd, IDC_EXP_SEL_FRAMES));
if (imp->prev_type != MaxEggExpOptions::AT_chan) imp->ClearNodeList(hWnd);
imp->prev_type = MaxEggExpOptions::AT_chan;
return TRUE;
}
break;
case IDC_BOTH:
if (HIWORD(wParam) == BN_CLICKED) {
SetWindowText(GetDlgItem(hWnd, IDC_EXPORT_SELECTED),
"Export Models:");
enableAnimRadios(hWnd, ANIM_RAD_ALL);
showAnimControls(hWnd, TRUE);
enableAnimControls(hWnd, IsDlgButtonChecked(hWnd, IDC_EXP_SEL_FRAMES));
if (imp->prev_type == MaxEggExpOptions::AT_chan) imp->ClearNodeList(hWnd);
imp->prev_type = MaxEggExpOptions::AT_both;
return TRUE;
}
break;
case IDC_POSE:
if (HIWORD(wParam) == BN_CLICKED) {
SetWindowText(GetDlgItem(hWnd, IDC_EXPORT_SELECTED),
"Export Meshes:");
enableAnimRadios(hWnd, ANIM_RAD_EXPSEL);
showAnimControls(hWnd, FALSE);
enableAnimControls(hWnd, TRUE);
CheckRadioButton(hWnd, IDC_EXP_ALL_FRAMES, IDC_EXP_SEL_FRAMES, IDC_EXP_SEL_FRAMES);
if (imp->prev_type == MaxEggExpOptions::AT_chan) imp->ClearNodeList(hWnd);
imp->prev_type = MaxEggExpOptions::AT_pose;
return TRUE;
}
break;
case IDC_EXP_ALL_FRAMES:
if (HIWORD(wParam) == BN_CLICKED) {
enableAnimControls(hWnd, FALSE);
return TRUE;
}
break;
case IDC_EXP_SEL_FRAMES:
if (HIWORD(wParam) == BN_CLICKED) {
enableAnimControls(hWnd, TRUE);
return TRUE;
}
break;
case IDC_EXPORT_ALL:
if (HIWORD(wParam) == BN_CLICKED) {
enableChooserControls(hWnd, FALSE);
return TRUE;
}
break;
case IDC_EXPORT_SELECTED:
if (HIWORD(wParam) == BN_CLICKED) {
enableChooserControls(hWnd, TRUE);
return TRUE;
}
break;
case IDC_ADD_EXPORT:
{
if (!imp->choosingNodes) {
AddNodeCB PickCB(imp, hWnd);
imp->choosingNodes = true;
imp->maxInterface->DoHitByNameDialog(&PickCB);
imp->choosingNodes = false;
}
}
return TRUE; break;
case IDC_REMOVE_EXPORT:
{
if (!imp->choosingNodes) {
imp->choosingNodes = true;
RemoveNodeCB PickCB(imp, hWnd);
imp->maxInterface->DoHitByNameDialog(&PickCB);
imp->choosingNodes = false;
}
}
return TRUE; break;
case IDC_OK:
if (imp->UpdateFromUI(hWnd)) EndDialog(hWnd, TRUE);
return TRUE; break;
case IDC_CANCEL:
EndDialog(hWnd, FALSE);
return TRUE; break;
case IDC_BROWSE:
OPENFILENAME ofn;
strcpy(tempFilename, GetICustEditT(GetDlgItem(hWnd, IDC_FILENAME)));
memset(&ofn, 0, sizeof(ofn));
ofn.nMaxFile = 2047;
ofn.lpstrFile = tempFilename;
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST;
ofn.lpstrDefExt = "egg";
ofn.lpstrFilter = "Panda3D Egg Files (*.egg)\0*.egg\0All Files (*.*)\0*.*\0";
SetFocus(GetDlgItem(hWnd, IDC_FILENAME));
if (GetSaveFileName(&ofn))
SetICustEdit(hWnd, IDC_FILENAME, ofn.lpstrFile);
//else {
// char buf[255];
// sprintf(buf, "%d", CommDlgExtendedError());
// MessageBox(hWnd, buf, "Error on GetSaveFileName", MB_OK);
//}
return TRUE; break;
case IDC_CHECK1:
if (IsDlgButtonChecked(hWnd, IDC_CHECK1))
if (MessageBox(hWnd, "Warning: Exporting double-sided polygons can severely hurt "
"performance in Panda3D.\n\nAre you sure you want to export them?",
"Panda3D Exporter", MB_YESNO | MB_ICONQUESTION) != IDYES)
CheckDlgButton(hWnd, IDC_CHECK1, BST_UNCHECKED);
return TRUE; break;
default:
//char buf[255];
//sprintf(buf, "%d", LOWORD(wParam));
//MessageBox(hWnd, buf, "Unknown WParam", MB_OK);
break;
}
}
return FALSE;
}
void MaxEggExpOptions::SetAnimRange() {
// Get the start and end frames and the animation frame rate from Max
Interval anim_range = maxInterface->GetAnimRange();
minFrame = anim_range.Start()/GetTicksPerFrame();
maxFrame = anim_range.End()/GetTicksPerFrame();
}
void MaxEggExpOptions::UpdateUI(HWND hWnd) {
int typeButton = IDC_MODEL;
int anim_exp = sf == INT_MIN ? IDC_EXP_ALL_FRAMES : IDC_EXP_SEL_FRAMES;
int model_exp = expWholeScene ? IDC_EXPORT_ALL : IDC_EXPORT_SELECTED;
switch (anim_type) {
case AT_chan: typeButton = IDC_ANIMATION; break;
case AT_both: typeButton = IDC_BOTH; break;
case AT_pose: typeButton = IDC_POSE; break;
}
prev_type = anim_type;
CheckRadioButton(hWnd, IDC_MODEL, IDC_POSE, typeButton);
SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(typeButton, BN_CLICKED), 0);
CheckRadioButton(hWnd, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, model_exp);
SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(model_exp, BN_CLICKED), 0);
CheckRadioButton(hWnd, IDC_EXP_ALL_FRAMES, IDC_EXP_SEL_FRAMES, anim_exp);
SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(anim_exp, BN_CLICKED), 0);
CheckDlgButton(hWnd, IDC_CHECK1,
dblSided ? BST_CHECKED : BST_UNCHECKED);
SetICustEdit(hWnd, IDC_FILENAME, filename);
if (sf != INT_MIN) {
SetICustEdit(hWnd, IDC_SF, sf);
SetICustEdit(hWnd, IDC_EF, ef);
}
else {
SetICustEdit(hWnd, IDC_SF, minFrame);
SetICustEdit(hWnd, IDC_EF, maxFrame);
}
RefreshNodeList(hWnd);
}
void MaxEggExpOptions::ClearNodeList(HWND hWnd) {
numNodes = 0;
RefreshNodeList(hWnd);
}
void MaxEggExpOptions::RefreshNodeList(HWND hWnd) {
//Clear and repopulate the node box
HWND nodeLB = GetDlgItem(hWnd, IDC_LIST_EXPORT);
SendMessage(nodeLB, LB_RESETCONTENT, 0, 0);
for (int i = 0; i < numNodes; i++) {
INode *temp = maxInterface->GetINodeByHandle(GetNode(i));
TCHAR *name = _T("Unknown Node");
if (temp) name = temp->GetName();
SendMessage(nodeLB, LB_ADDSTRING, 0, (LPARAM)name);
}
}
bool MaxEggExpOptions::UpdateFromUI(HWND hWnd) {
BOOL valid;
Anim_Type newAnimType;
int newSF = INT_MIN, newEF = INT_MIN;
char msg[1024];
if (IsDlgButtonChecked(hWnd, IDC_MODEL)) newAnimType = AT_model;
else if (IsDlgButtonChecked(hWnd, IDC_ANIMATION)) newAnimType = AT_chan;
else if (IsDlgButtonChecked(hWnd, IDC_BOTH)) newAnimType = AT_both;
else newAnimType = AT_pose;
if (newAnimType != AT_model && IsDlgButtonChecked(hWnd, IDC_EXP_SEL_FRAMES)) {
newSF = GetICustEditI(GetDlgItem(hWnd, IDC_SF), &valid);
if (!valid) {
MessageBox(hWnd, "Start Frame must be an integer", "Invalid Value", MB_OK | MB_ICONEXCLAMATION);
return false;
}
if (newSF < minFrame) {
sprintf(msg, "Start Frame must be at least %d", minFrame);
MessageBox(hWnd, msg, "Invalid Value", MB_OK | MB_ICONEXCLAMATION);
return false;
}
if (newSF > maxFrame) {
sprintf(msg, "Start Frame must be at most %d", maxFrame);
MessageBox(hWnd, msg, "Invalid Value", MB_OK | MB_ICONEXCLAMATION);
return false;
}
if (newAnimType != AT_pose) {
newEF = GetICustEditI(GetDlgItem(hWnd, IDC_EF), &valid);
if (!valid) {
MessageBox(hWnd, "End Frame must be an integer", "Invalid Value", MB_OK | MB_ICONEXCLAMATION);
return false;
}
if (newEF > maxFrame) {
sprintf(msg, "End Frame must be at most %d", maxFrame);
MessageBox(hWnd, msg, "Invalid Value", MB_OK | MB_ICONEXCLAMATION);
return false;
}
if (newEF < newSF) {
MessageBox(hWnd, "End Frame must be greater than the start frame", "Invalid Value", MB_OK | MB_ICONEXCLAMATION);
return false;
}
}
}
char *temp = GetICustEditT(GetDlgItem(hWnd, IDC_FILENAME));
if (!strlen(temp)) {
MessageBox(hWnd, "The filename cannot be empty", "Invalid Value", MB_OK | MB_ICONEXCLAMATION);
return false;
}
if (strlen(temp) < 4 || strncmp(".egg", temp+(strlen(temp) - 4), 4))
sprintf(filename, "%s.egg", temp);
else strcpy(filename, temp);
temp = strrchr(filename, '\\');
if (!temp) temp = filename;
else temp++;
if (strlen(temp) > sizeof(shortName))
sprintf(shortName, "%.*s...", sizeof(shortName)-4, temp);
else {
strcpy(shortName, temp);
shortName[strlen(shortName) - 4] = NULL; //Cut off the .egg
}
dblSided = IsDlgButtonChecked(hWnd, IDC_CHECK1);
expWholeScene = IsDlgButtonChecked(hWnd, IDC_EXPORT_ALL);
sf = newSF; ef = newEF; anim_type = newAnimType;
return true;
}
bool MaxEggExpOptions::FindNode(ULONG INodeHandle) {
for (int i = 0; i < numNodes; i++)
if (nodeList[i] == INodeHandle) return true;
return false;
}
void MaxEggExpOptions::AddNode(ULONG INodeHandle) {
if (FindNode(INodeHandle)) return;
if (numNodes >= maxNodes) {
ULONG *newList;
maxNodes *= 2;
newList = new ULONG[maxNodes];
for (int i = 0; i < numNodes; i++) newList[i] = nodeList[i];
delete [] nodeList;
nodeList = newList;
}
nodeList[numNodes++] = INodeHandle;
}
void MaxEggExpOptions::CullBadNodes() {
if (!maxInterface) return;
int i = 0, j = 0;
while (j < numNodes) {
if (!maxInterface->GetINodeByHandle(nodeList[i])) j++;
else nodeList[i++] = nodeList[j++];
}
numNodes = i;
}
void MaxEggExpOptions::RemoveNode(int i) {
if (i >= 0 && i < numNodes) {
for (int j = i+1; j < numNodes;) nodeList[i++] = nodeList[j++];
--numNodes;
}
}
void MaxEggExpOptions::RemoveNodeByHandle(ULONG INodeHandle) {
for (int i = 0; i < numNodes; i++)
if (nodeList[i] == INodeHandle) {
RemoveNode(i);
return;
}
}
IOResult MaxEggExpOptions::Save(ISave *isave) {
isave->BeginChunk(CHUNK_EGG_EXP_OPTIONS);
ChunkSave(isave, CHUNK_ANIM_TYPE, anim_type);
ChunkSave(isave, CHUNK_FILENAME, filename);
ChunkSave(isave, CHUNK_SHORTNAME, shortName);
ChunkSave(isave, CHUNK_SF, sf);
ChunkSave(isave, CHUNK_EF, ef);
ChunkSave(isave, CHUNK_DBL_SIDED, dblSided);
ChunkSave(isave, CHUNK_EGG_CHECKED, checked);
ChunkSave(isave, CHUNK_EXPORT_FULL, expWholeScene);
isave->BeginChunk(CHUNK_NODE_LIST);
for (int i = 0; i < numNodes; i++)
ChunkSave(isave, CHUNK_NODE_HANDLE, nodeList[i]);
isave->EndChunk();
isave->EndChunk();
return IO_OK;
}
IOResult MaxEggExpOptions::Load(ILoad *iload) {
IOResult res = iload->OpenChunk();
while (res == IO_OK) {
switch(iload->CurChunkID()) {
case CHUNK_ANIM_TYPE: anim_type = (Anim_Type)ChunkLoadInt(iload); break;
case CHUNK_FILENAME: ChunkLoadString(iload, filename, sizeof(filename)); break;
case CHUNK_SHORTNAME: ChunkLoadString(iload, shortName, sizeof(shortName)); break;
case CHUNK_SF: sf = ChunkLoadInt(iload); break;
case CHUNK_EF: ef = ChunkLoadInt(iload); break;
case CHUNK_DBL_SIDED: dblSided = ChunkLoadBool(iload); break;
case CHUNK_EGG_CHECKED: checked = ChunkLoadBool(iload); break;
case CHUNK_EXPORT_FULL: expWholeScene = ChunkLoadBool(iload); break;
case CHUNK_NODE_LIST:
res = iload->OpenChunk();
while (res == IO_OK) {
if (iload->CurChunkID() == CHUNK_NODE_HANDLE) AddNode(ChunkLoadULONG(iload));
iload->CloseChunk();
res = iload->OpenChunk();
}
break;
}
iload->CloseChunk();
res = iload->OpenChunk();
}
if (res == IO_END) return IO_OK;
return IO_ERROR;
}
/*!
* This method creates and triggers the exporter. Basically it takes the
* user's options and builds a command-line parameter list from it.
* It then invokes the converter pretending it was invoked as a standalone
* program. BIG WARNING: The converter stuff often does exit() if the
* command line arguments are displeasing.
*/
bool MaxEggExpOptions::DoExport(IObjParam *ip, bool autoOverwrite, bool saveLog)
{
MaxToEgg *pmteConverter = new MaxToEgg();
char *apcParameters[64];
char pszSF[10], pszEF[10];
char acOutputFilename[MAX_PATH];
char curFilename[MAX_PATH];
int iParameterCount=0;
//Initialize our global error logger
if (saveLog)
Logger::globalLoggingInstance = new Logger( Logger::PIPE_TO_FILE, "MaxEggLog.txt" );
else Logger::globalLoggingInstance = new Logger( Logger::PIPE_TO_DEV_NULL, "" );
//Set the various logging levels for the subsystems.
Logger::SetOneErrorMask( ME, Logger::SAT_ALL );
Logger::SetOneErrorMask( MTE, Logger::SAT_NULL_ERROR |
Logger::SAT_CRITICAL_ERROR |
Logger::SAT_PARAMETER_INVALID_ERROR |
Logger::SAT_OTHER_ERROR | Logger::SAT_HIGH_LEVEL );
Logger::SetOneErrorMask( MTEC, Logger::SAT_NULL_ERROR |
Logger::SAT_CRITICAL_ERROR |
Logger::SAT_PARAMETER_INVALID_ERROR |
Logger::SAT_OTHER_ERROR | Logger::SAT_HIGH_LEVEL |
Logger::SAT_MEDIUM_LEVEL | Logger::SAT_LOW_LEVEL |
Logger::SAT_DEBUG_SPAM_LEVEL );
Logger::SetOneErrorMask( MNEG, Logger::SAT_NULL_ERROR |
Logger::SAT_CRITICAL_ERROR |
Logger::SAT_PARAMETER_INVALID_ERROR |
Logger::SAT_OTHER_ERROR | Logger::SAT_HIGH_LEVEL |
Logger::SAT_MEDIUM_LEVEL | Logger::SAT_LOW_LEVEL );
Logger::SetOneErrorMask( MNEG_GEOMETRY_GENERATION, Logger::SAT_NULL_ERROR |
Logger::SAT_CRITICAL_ERROR |
Logger::SAT_PARAMETER_INVALID_ERROR |
Logger::SAT_OTHER_ERROR | Logger::SAT_HIGH_LEVEL |
Logger::SAT_MEDIUM_LEVEL | Logger::SAT_LOW_LEVEL );
Logger::SetOneErrorMask( LLOGGING, Logger::SAT_ALL );
Logger::FunctionEntry( "MaxEggPlugin::DoExport" );
// Copy the output filename so that it can be modified if necessary
strncpy(acOutputFilename, filename, MAX_PATH-1);
acOutputFilename[MAX_PATH-1]=0;
// Panda reaaaaaaaaly wants the extension to be in lower case.
// So if we see a .egg at the end, lower case it.
if ((strlen(acOutputFilename)>4) &&
(stricmp(acOutputFilename+strlen(acOutputFilename)-4,".egg")==0)) {
strlwr(acOutputFilename+strlen(acOutputFilename)-4);
}
pmteConverter->SetMaxInterface((Interface*)ip);
// Set the command-line arguments
// ARGV[0] = program name
apcParameters[iParameterCount++]="MaxEggPlugin";
// ARGV[1] = Input file
// Use a bogus input filename that exists
apcParameters[iParameterCount++]="nul.max";
// ARGV[2,3] = Animation options
// Check if there is an animation to be saved and what type of animation it
// will be saved as. Then set the animation option.
apcParameters[iParameterCount++]="-a";
switch (anim_type) {
case AT_chan: apcParameters[iParameterCount++]="chan"; break;
case AT_pose: apcParameters[iParameterCount++]="pose"; break;
case AT_both: apcParameters[iParameterCount++]="both"; break;
case AT_model:
default: apcParameters[iParameterCount++]="model"; break;
}
//Start Frame
//If the export options need a start frame and we have one
//then use it
if (sf != INT_MIN && anim_type != AT_model) {
sprintf(pszSF, "%d", sf);
apcParameters[iParameterCount++] = "-sf";
apcParameters[iParameterCount++] = pszSF;
}
//Start Frame
//If the export options need an end frame and we have one
//then use it
if (sf != INT_MIN && (anim_type == AT_chan || anim_type == AT_both)) {
sprintf(pszEF, "%d", ef);
apcParameters[iParameterCount++] = "-ef";
apcParameters[iParameterCount++] = pszEF;
}
// Doublesided: This option may be diabled in the converter
// but this is here for when it is enabled
if (dblSided) apcParameters[iParameterCount++] = "-bface";
// Final ARGV = Output file
// Pass in the output filename
// Output file has to be passed in with the -o parameter in order to be able
// to overwrite an existing file
if (autoOverwrite) apcParameters[iParameterCount++]="-o";
apcParameters[iParameterCount++]=acOutputFilename;
apcParameters[iParameterCount]=0;
// Parse the command line and run the converter
pmteConverter->parse_command_line(iParameterCount, apcParameters);
if (expWholeScene) pmteConverter->Run(NULL, 0);
else pmteConverter->Run(nodeList, numNodes);
successful = pmteConverter->IsSuccessful();
// This was put in try block because originally deleting pmteConverter
// would throw an exception. That no longer happens, but this is still
// here for good measure
try {
Logger::Log(MTEC, Logger::SAT_MEDIUM_LEVEL, "before deleting pmteconverter");
delete pmteConverter;
} catch (...) {
Logger::Log(MTEC, Logger::SAT_MEDIUM_LEVEL, "before error message window");
MessageBox(ip->GetMAXHWnd(), "I just got an unknown exception.",
"Panda3D Converter", MB_OK);
}
Logger::Log(MTEC, Logger::SAT_MEDIUM_LEVEL, "before logger function exit");
Logger::FunctionExit();
//Free the error logger
if ( Logger::globalLoggingInstance )
delete Logger::globalLoggingInstance;
return successful;
}

View File

@ -0,0 +1,114 @@
/*
MaxEggExpOptions.h
Created by Phillip Saltzman, 2/15/05
Carnegie Mellon University, Entetainment Technology Center
This file contains a class that allows users to specify
export options, and then execute the export
*/
#ifndef __MaxEggExpOptions__H
#define __MaxEggExpOptions__H
#pragma conform(forScope, off)
//Includes & Definitions
#include "maxToEgg.h"
#include "windef.h"
/* Error-Reporting Includes */
#include "Logger.h"
#define ME Logger::ST_MAP_ME_TO_APP_SPECIFIC_SYSTEM6
#define MNEG Logger::ST_MAP_ME_TO_APP_SPECIFIC_SYSTEM2
#define MNEG_GEOMETRY_GENERATION Logger::ST_MAP_ME_TO_APP_SPECIFIC_SYSTEM3
/* Externed Globals */
extern HINSTANCE hInstance;
//Save/load chunk definitions
#define CHUNK_OVERWRITE_FLAG 0x1000
#define CHUNK_PVIEW_FLAG 0x1001
#define CHUNK_LOG_OUTPUT 0x1002
#define CHUNK_EGG_EXP_OPTIONS 0x1100
#define CHUNK_ANIM_TYPE 0x1101
#define CHUNK_EGG_CHECKED 0x1102
#define CHUNK_DBL_SIDED 0x1103
#define CHUNK_SF 0x1104
#define CHUNK_EF 0x1105
#define CHUNK_FILENAME 0x1106
#define CHUNK_SHORTNAME 0x1107
#define CHUNK_EXPORT_FULL 0x1108
#define CHUNK_NODE_LIST 0x1200
#define CHUNK_NODE_HANDLE 0x1201
//Global functions
void ChunkSave(ISave *isave, int chunkid, int value);
void ChunkSave(ISave *isave, int chunkid, bool value);
void ChunkSave(ISave *isave, int chunkid, char *value);
char *ChunkLoadString(ILoad *iload, char *buffer, int maxBytes);
int ChunkLoadInt(ILoad *iload);
bool ChunkLoadBool(ILoad *iload);
void SetICustEdit(HWND wnd, int nIDDlgItem, char *text);
BOOL CALLBACK MaxEggExpOptionsProc( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam );
class MaxEggExpOptions
{
friend class MaxEggPlugin;
public:
enum Anim_Type {
AT_none,
AT_model,
AT_chan,
AT_pose,
AT_strobe,
AT_both
};
protected:
Anim_Type anim_type;
int sf, ef;
int minFrame, maxFrame;
bool dblSided, expWholeScene;
char shortName[256];
bool successful;
ULONG *nodeList;
int numNodes;
int maxNodes;
public:
bool checked;
char filename[2048];
IObjParam *maxInterface;
bool choosingNodes;
Anim_Type prev_type;
MaxEggExpOptions();
virtual ~MaxEggExpOptions() { delete [] nodeList;}
bool DoExport(IObjParam *ip, bool autoOverwrite, bool saveLog);
void UpdateUI(HWND hWnd);
bool UpdateFromUI(HWND hWnd);
void RefreshNodeList(HWND hWnd);
void SetAnimRange();
bool FindNode(ULONG INodeHandle); //returns true if the node is already in the list
void AddNode(ULONG INodeHandle);
void RemoveNode(int i);
void RemoveNodeByHandle(ULONG INodeHandle);
void ClearNodeList(HWND hWnd);
void CullBadNodes();
ULONG GetNode(int i) { return (i >= 0 && i < maxNodes) ? nodeList[i] : ULONG_MAX; }
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
//int DoExport(const TCHAR *name,ExpInterface *ei,
// Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0);
};
#endif // __MaxEggExpOptions__H

View File

@ -28,13 +28,17 @@ MaxToEgg::MaxToEgg() : SomethingToEgg("3D Studio Max",".max")
add_transform_options();
set_program_description("This program converts 3D Studio Max model files to egg.");
add_option("p", "", 0,
/*add_option("p", "", 0,
"Generate polygon output only. Convert scene to triangle mesh "
"before converting.", &MaxToEgg::dispatch_none, &alertOnBegin);
"before converting.", &MaxToEgg::dispatch_none, &alertOnBegin);*/
add_option("bface", "", 0,
"Export all polygons as double-sided ",
&MaxToEgg::dispatch_none, &doubleSided);
//Fill in the member variables.
pMaxInterface = null;
successfulOutput = false;
alertOnBegin = false;
confirmExport = true;
doubleSided = false;
}
/* IsSuccessful() - Indicates if conversion was successful.
@ -52,7 +56,7 @@ char *MaxToEgg::MyClassName()
/* Run() - Runs the conversion. Creates a MaxToEggConverter, populates it
with the scene graph, and then writes out the egg file.
*/
void MaxToEgg::Run()
void MaxToEgg::Run(ULONG *selection_list, int len)
{
MaxToEggConverter converter;
@ -66,9 +70,11 @@ void MaxToEgg::Run()
converter.set_egg_data( &_data, false );
// applies the parameters from the command line options
apply_parameters(converter);
converter.set_double_sided(doubleSided);
converter.set_selection_list(selection_list, len);
//Now, do the actual file conversion.
if (converter.convert_file(_input_filename)) {
if (confirmExport && converter.convert_file(_input_filename)) {
successfulOutput=true;
write_egg_file();
Logger::Log( MTE, Logger::SAT_DEBUG_SPAM_LEVEL, "Egg file written!" );
@ -86,3 +92,34 @@ void MaxToEgg::SetMaxInterface(Interface *pInterface)
{
pMaxInterface = pInterface;
}
bool MaxToEgg::handle_args(Args &args) {
char msg[3072];
//If "auto overwrite" was not checked, ask if the user wishes to overwrite the file
if (_allow_last_param && !_got_output_filename && args.size() > 1) {
_got_output_filename = true;
_output_filename = Filename::from_os_specific(args.back());
args.pop_back();
if (!verify_output_file_safe()) {
sprintf(msg, "Overwrite file \"%s\"?", _output_filename.to_os_specific().c_str());
confirmExport =
( MessageBox(pMaxInterface->GetMAXHWnd(), msg, "Panda3D Exporter", MB_YESNO | MB_ICONQUESTION)
== IDYES );
}
}
//Attempt to catch if the output file is read-only
if (confirmExport) {
_output_filename.make_dir();
if (access(Filename(_output_filename.get_dirname()).to_os_specific().c_str(), 2) ||
(access(_output_filename.to_os_specific().c_str(), 2) && errno != ENOENT)) {
sprintf(msg, "Error attempting to open \"%s\"\n\nDestination file is in use or read-only", _output_filename.to_os_specific().c_str());
MessageBox(pMaxInterface->GetMAXHWnd(), msg, "Panda3D Exporter", MB_OK | MB_ICONERROR);
confirmExport = false;
}
}
return SomethingToEgg::handle_args(args);
}

View File

@ -36,7 +36,7 @@ class MaxToEgg : public SomethingToEgg
protected:
// If true, various windows pop-up alerts will announce when certain tasks
// begin.
bool alertOnBegin;
bool confirmExport;
// The local pointer to the 3ds max interface we keep around to get the
// scene graph. If we ever get this to run standalone, we'll need an
// alternate way to set this other than through MaxEggPlugin.
@ -44,6 +44,8 @@ class MaxToEgg : public SomethingToEgg
// False initially, but premanently switches to true when a file is
// sucessfully converted.
bool successfulOutput;
bool doubleSided;
virtual bool handle_args(Args &args);
public:
MaxToEgg();
@ -51,7 +53,7 @@ class MaxToEgg : public SomethingToEgg
bool IsSuccessful();
//Returns a pointer to the class name.
char *MyClassName();
void Run();
void Run(ULONG *selection_list, int len);
void SetMaxInterface(Interface *pInterface);
};

View File

@ -25,7 +25,11 @@
/* 3ds Max Includes, with bonus(!) memory protection
*/
#ifdef MAX5
//Disable the "Too many actual parameters in istdplug.h" warning in Max5
#pragma warning(push)
#pragma warning(disable: 4002)
#include "pre_max_include.h"
#endif
#include "Max.h"
@ -36,10 +40,13 @@
#include "resource.h"
#include "stdmat.h"
#include "phyexp.h"
#include "surf_api.h"
#ifdef MAX5
#include "post_max_include.h"
#pragma warning(pop)
#endif
/* Panda Includes
*/
#include "eggCoordinateSystem.h"
@ -49,6 +56,7 @@
#include "eggTexture.h"
#include "eggVertex.h"
#include "eggVertexPool.h"
#include "eggNurbsCurve.h"
#include "pandatoolbase.h"
#include "somethingToEgg.h"
#include "somethingToEggConverter.h"
@ -95,8 +103,13 @@ class MaxToEggConverter : public SomethingToEggConverter {
//Sets the interface to 3dsMax.
void setMaxInterface(Interface *pInterface);
void set_selection_list(ULONG *list, int len) {
_selection_list = list; _selection_len = len; }
void set_double_sided(bool flag) {double_sided = flag;}
private:
double _current_frame;
ULONG *_selection_list; int _selection_len;
bool convert_flip(double start_frame, double end_frame,
double frame_inc, double output_frame_rate);
@ -122,10 +135,9 @@ class MaxToEggConverter : public SomethingToEggConverter {
const string &nurbs_name,
EggGroupNode *egg_group,
int trim_curve_index);
void make_nurbs_curve(const MDagPath &dag_path,
const MFnNurbsCurve &curve,
EggGroup *group);
*/
*/
bool make_nurbs_curve(NURBSCVCurve *curve, const string &name,
TimeValue time, EggGroup *egg_group);
void make_polyset(INode *max_node,
Mesh *mesh,
EggGroup *egg_group,
@ -162,6 +174,7 @@ class MaxToEggConverter : public SomethingToEggConverter {
MaxNodeTree _tree;
int _cur_tref;
bool double_sided;
public:
//MayaShaders _shaders;

View File

@ -29,12 +29,16 @@
#include "namable.h"
#ifdef MAX5
//Disable the "Too many actual parameters in istdplug.h" warning in Max5
#pragma warning(push)
#pragma warning(disable: 4002)
#include "pre_max_include.h"
#endif
#include <Max.h>
#include "bipexp.h"
#ifdef MAX5
#include "post_max_include.h"
#pragma warning(pop)
#endif
class EggGroup;

View File

@ -23,11 +23,20 @@
#include "eggXfmSAnim.h"
#include "eggData.h"
#ifdef MAX5
//Disable the "Too many actual parameters in istdplug.h" warning in Max5
#pragma warning(push)
#pragma warning(disable: 4002)
#include "pre_max_include.h"
#endif
#include "Max.h"
#ifdef MAX5
#include "post_max_include.h"
#pragma warning(pop)
#endif
#include "maxToEggConverter.h"
////////////////////////////////////////////////////////////////////
// Function: MaxNodeTree::Constructor
// Access: Public
@ -73,13 +82,30 @@ build_joint(INode *max_node, MaxNodeDesc *node_joint) {
return node_desc;
}
bool MaxNodeTree::node_in_list(ULONG handle, ULONG *list, int len) {
if (!list) return true;
for (int i = 0; i < len; i++)
if (list[i] == handle) return true;
return false;
}
bool MaxNodeTree::is_joint(INode *node) {
Control *c = node->GetTMController();
return (node->GetBoneNodeOnOff() || //joints
(c && //bipeds
((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) ||
(c->ClassID() == BIPBODY_CONTROL_CLASS_ID) ||
(c->ClassID() == FOOTPRINT_CLASS_ID))));
}
bool MaxNodeTree::
r_build_hierarchy(INode *root) {
build_node(root);
r_build_hierarchy(INode *root, ULONG *selection_list, int len) {
if (node_in_list(root->GetHandle(), selection_list, len))
build_node(root);
// Export children
for ( int i = 0; i < root->NumberOfChildren(); i++ ) {
// *** Should probably be checking the return value of the following line
r_build_hierarchy(root->GetChildNode(i));
r_build_hierarchy(root->GetChildNode(i), selection_list, len);
}
return true;
}
@ -90,7 +116,7 @@ r_build_hierarchy(INode *root) {
// up the corresponding tree.
////////////////////////////////////////////////////////////////////
bool MaxNodeTree::
build_complete_hierarchy(INode *root) {
build_complete_hierarchy(INode *root, ULONG *selection_list, int len) {
// Get the entire Max scene.
if (root == NULL) {
@ -99,7 +125,7 @@ build_complete_hierarchy(INode *root) {
}
bool all_ok = true;
r_build_hierarchy(root);
r_build_hierarchy(root, selection_list, len);
if (all_ok) {
_root->check_pseudo_joints(false);
@ -462,5 +488,8 @@ find_node(INode* max_node)
MaxNodeDesc *MaxNodeTree::
find_joint(INode* max_node)
{
return find_node(max_node)->_joint_entry;
MaxNodeDesc *node = find_node(max_node);
if (!node || (is_joint(max_node) && !node->is_node_joint()))
node = build_node(max_node);
return node->_joint_entry;
}

View File

@ -37,7 +37,7 @@ public:
MaxNodeTree();
MaxNodeDesc *build_node(INode *max_node);
MaxNodeDesc *build_joint(INode *max_node, MaxNodeDesc *node_joint);
bool build_complete_hierarchy(INode *root);
bool build_complete_hierarchy(INode *root, ULONG *selection_list, int len);
bool build_selected_hierarchy(INode *root);
MaxNodeDesc *find_node(INode *max_node);
MaxNodeDesc *find_joint(INode *max_node);
@ -61,7 +61,9 @@ private:
MaxNodeDesc *r_build_node(INode *max_node);
MaxNodeDesc *r_build_joint(MaxNodeDesc *node_desc, INode *max_node);
bool r_build_hierarchy(INode *root);
bool node_in_list(ULONG handle, ULONG *list, int len);
bool r_build_hierarchy(INode *root, ULONG *selection_list, int len);
bool is_joint(INode *node);
typedef pmap<ULONG, MaxNodeDesc *> NodesByPath;
NodesByPath _nodes_by_path;

View File

@ -39,6 +39,8 @@ MaxToEggConverter(const string &program_name) :
_transform_type = TT_model;
_cur_tref = 0;
_current_frame = 0;
_selection_list = NULL;
_selection_len = 0;
}
////////////////////////////////////////////////////////////////////
@ -195,7 +197,7 @@ convert_max(bool from_selection) {
if (_from_selection) {
all_ok = _tree.build_selected_hierarchy(maxInterface->GetRootNode());
} else {
all_ok = _tree.build_complete_hierarchy(maxInterface->GetRootNode());
all_ok = _tree.build_complete_hierarchy(maxInterface->GetRootNode(), _selection_list, _selection_len);
}
if (all_ok) {
@ -398,22 +400,23 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc,
// Find all joints in the hierarchy
MaxNodeDesc *node_desc = _tree.get_node(i);
if (node_desc->is_joint()) {
tgroup = new EggGroup();
INode *max_node = node_desc->get_max_node();
tgroup = new EggGroup();
INode *max_node = node_desc->get_max_node();
if (node_desc->_parent && node_desc->_parent->is_joint()) {
// If this joint also has a joint as a parent, the parent's
// transformation has to be divided out of this joint's TM
get_joint_transform(max_node, node_desc->_parent->get_max_node(),
tgroup);
} else {
get_joint_transform(max_node, NULL, tgroup);
}
if (node_desc->_parent && node_desc->_parent->is_joint()) {
// If this joint also has a joint as a parent, the parent's
// transformation has to be divided out of this joint's TM
get_joint_transform(max_node, node_desc->_parent->get_max_node(),
tgroup);
} else {
get_joint_transform(max_node, NULL, tgroup);
}
EggXfmSAnim *anim = _tree.get_egg_anim(node_desc);
if (!anim->add_data(tgroup->get_transform())) {
// *** log an error
}
delete tgroup;
// *** log an error
}
delete tgroup;
}
}
@ -441,10 +444,10 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc,
////////////////////////////////////////////////////////////////////
bool MaxToEggConverter::
convert_hierarchy(EggGroupNode *egg_root) {
int num_nodes = _tree.get_num_nodes();
//int num_nodes = _tree.get_num_nodes();
_tree.clear_egg(&get_egg_data(), egg_root, NULL);
for (int i = 0; i < num_nodes; i++) {
for (int i = 0; i < _tree.get_num_nodes(); i++) {
if (!process_model_node(_tree.get_node(i))) {
return false;
}
@ -480,15 +483,15 @@ process_model_node(MaxNodeDesc *node_desc) {
state = max_node->EvalWorldState(_current_frame * GetTicksPerFrame());
if (node_desc->is_joint()) {
EggGroup *egg_group = _tree.get_egg_group(node_desc);
// Don't bother with joints unless we're getting an animatable
// model.
if (_animation_convert == AC_model) {
EggGroup *egg_group = _tree.get_egg_group(node_desc);
get_joint_transform(max_node, egg_group);
}
} else {
if (state.obj) {
EggGroup *egg_group;
EggGroup *egg_group = NULL;
TriObject *myMaxTriObject;
Mesh max_mesh;
//Call the correct exporter based on what type of object this is.
@ -497,10 +500,10 @@ process_model_node(MaxNodeDesc *node_desc) {
case GEOMOBJECT_CLASS_ID:
Logger::Log( MTEC, Logger::SAT_HIGH_LEVEL,
"Found a geometric object in the hierarchy!" );
egg_group = _tree.get_egg_group(node_desc);
egg_group = _tree.get_egg_group(node_desc);
get_transform(max_node, egg_group);
//Try converting this geometric object to a mesh we can use.
//Try converting this geometric object to a mesh we can use.
if (!state.obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) {
Logger::Log(MTEC, Logger::SAT_OTHER_ERROR,
"Cannot create geometry from state.obj!");
@ -523,7 +526,25 @@ process_model_node(MaxNodeDesc *node_desc) {
if (myMaxTriObject != state.obj)
delete myMaxTriObject;
break;
case SHAPE_CLASS_ID:
if (state.obj->ClassID() == EDITABLE_SURF_CLASS_ID) {
Logger::Log( MTEC, Logger::SAT_HIGH_LEVEL,
"Found a NURB object in the hierarchy!" );
NURBSSet getSet;
if (GetNURBSSet(state.obj, time, getSet, TRUE)) {
NURBSObject *nObj = getSet.GetNURBSObject(0);
if (nObj->GetType() == kNCVCurve) {
//It's a CV Curve, process it
egg_group = _tree.get_egg_group(node_desc);
get_transform(max_node, egg_group);
make_nurbs_curve((NURBSCVCurve *)nObj, string(max_node->GetName()),
time, egg_group);
}
}
}
break;
case CAMERA_CLASS_ID:
Logger::Log( MTEC, Logger::SAT_HIGH_LEVEL,
"Found a camera object in the hierarchy!" );
@ -538,6 +559,13 @@ process_model_node(MaxNodeDesc *node_desc) {
Logger::Log( MTEC, Logger::SAT_HIGH_LEVEL,
"Found a helper object in the hierarchy!" );
break;
/* default:
char buf[1024];
sprintf(buf, "Unknown Superclass ID: %x, ClassID: %x,%x", state.obj->SuperClassID(),
state.obj->ClassID().PartA(), state.obj->ClassID().PartB());
Logger::Log( MTEC, Logger::SAT_HIGH_LEVEL,
buf ); */
}
}
}
@ -1246,7 +1274,7 @@ make_trim_curve(const MFnNurbsCurve &curve, const string &nurbs_name,
}
return egg_curve;
}
} */
////////////////////////////////////////////////////////////////////
// Function: MaxToEggConverter::make_nurbs_curve
@ -1255,10 +1283,12 @@ make_trim_curve(const MFnNurbsCurve &curve, const string &nurbs_name,
// curve, not a trim curve) to a corresponding egg
// structure and attaches it to the indicated egg group.
////////////////////////////////////////////////////////////////////
void MaxToEggConverter::
make_nurbs_curve(const MDagPath &, const MFnNurbsCurve &curve,
EggGroup *egg_group) {
MStatus status;
bool MaxToEggConverter::
make_nurbs_curve(NURBSCVCurve *curve, const string &name,
TimeValue time, EggGroup *egg_group)
{
/* MStatus status;
string name = curve.name().asChar();
if (mayaegg_cat.is_spam()) {
@ -1290,12 +1320,19 @@ make_nurbs_curve(const MDagPath &, const MFnNurbsCurve &curve,
}
// MFnNurbsCurve::Form form = curve.form();
*/
int degree = curve.degree();
int cvs = curve.numCVs();
int knots = curve.numKnots();
int degree = curve->GetOrder();
int cvs = curve->GetNumCVs();
int knots = curve->GetNumKnots();
int i;
assert(knots == cvs + degree - 1);
if (knots != cvs + degree) {
char buf[1024];
sprintf(buf, "NURBS knots count incorrect. Order %d, CVs %d, knots %d", degree, cvs, knots);
Logger::Log( MTEC, Logger::SAT_HIGH_LEVEL, buf);
return false;
}
string vpool_name = name + ".cvs";
EggVertexPool *vpool = new EggVertexPool(vpool_name);
@ -1303,38 +1340,32 @@ make_nurbs_curve(const MDagPath &, const MFnNurbsCurve &curve,
EggNurbsCurve *egg_curve = new EggNurbsCurve(name);
egg_group->add_child(egg_curve);
egg_curve->setup(degree + 1, knots + 2);
egg_curve->setup(degree, knots);
int i;
egg_curve->set_knot(0, knot_array[0]);
for (i = 0; i < knots; i++) {
egg_curve->set_knot(i + 1, knot_array[i]);
}
egg_curve->set_knot(knots + 1, knot_array[knots - 1]);
for (i = 0; i < knots; i++)
egg_curve->set_knot(i, curve->GetKnot(i));
LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv();
for (i = 0; i < egg_curve->get_num_cvs(); i++) {
double v[4];
MStatus status = cv_array[i].get(v);
if (!status) {
status.perror("MPoint::get");
for (i = 0; i < cvs; i++) {
NURBSControlVertex *cv = curve->GetCV(i);
if (!cv) {
char buf[1024];
sprintf(buf, "Error getting CV %d", i);
Logger::Log( MTEC, Logger::SAT_HIGH_LEVEL, buf);
return false;
} else {
EggVertex vert;
LPoint4d p4d(v[0], v[1], v[2], v[3]);
LPoint4d p4d(0, 0, 0, 1.0);
cv->GetPosition(time, p4d[0], p4d[1], p4d[2]);
p4d = p4d * vertex_frame_inv;
vert.set_pos(p4d);
egg_curve->add_vertex(vpool->create_unique_vertex(vert));
}
}
MayaShader *shader = _shaders.find_shader_for_node(curve.object());
if (shader != (MayaShader *)NULL) {
set_shader_attributes(*egg_curve, *shader);
}
return true;
}
*/
////////////////////////////////////////////////////////////////////
// Function: MaxToEggConverter::make_polyset
@ -1348,7 +1379,7 @@ make_polyset(INode *max_node, Mesh *mesh,
EggGroup *egg_group, Shader *default_shader) {
Logger::Log( MTEC, Logger::SAT_MEDIUM_LEVEL, "Entered make_poly_set." );
bool double_sided = false;
//bool double_sided = false;
// *** I think this needs to have a plugin written to support
/*

View File

@ -1,6 +1,7 @@
#include "DllEntry.cpp"
#include "Logger.cpp"
#include "MaxEgg.cpp"
#include "MaxEggExpOptions.cpp"
#include "maxNodeDesc.cxx"
#include "MaxNodeTree.cxx"
#include "MaxToEgg.cpp"

View File

@ -1,48 +1,53 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by MaxEgg.rc
//
#define IDS_LIBDESCRIPTION 1
#define IDS_CATEGORY 2
#define IDS_CLASS_NAME 3
#define IDS_PARAMS 4
#define IDS_SPIN 5
#define IDD_PANEL 101
#define IDC_CLOSEBUTTON 1000
#define IDC_DOSTUFF 1000
#define IDC_CHECK1 1001
#define IDC_MAKE_BAM 1001
#define IDC_DONE 1002
#define IDC_ANIMATION 1003
#define IDC_MODEL 1004
#define IDC_CHAN 1005
#define IDC_POSE 1006
#define IDC_STROBE 1007
#define IDC_BOTH 1008
#define IDC_EDIT1 1009
#define IDC_CN 1009
#define IDC_SF 1010
#define IDC_IF 1011
#define IDC_EF 1012
#define IDC_SF_LABEL 1013
#define IDC_EF_LABEL 1014
#define IDC_IF_LABEL 1015
#define IDC_CN_LABEL 1016
#define IDC_RADIO1 1017
#define IDC_DONE2 1017
#define IDC_CANCEL 1017
#define IDC_RADIO2 1018
#define IDC_COLOR 1456
#define IDC_EDIT 1490
#define IDC_SPIN 1496
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1019
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by MaxEgg.rc
//
#define IDS_LIBDESCRIPTION 1
#define IDS_CATEGORY 2
#define IDS_CLASS_NAME 3
#define IDS_PARAMS 4
#define IDS_SPIN 5
#define IDD_PANEL 101
#define IDD_EGG_DETAILS 102
#define IDC_EGGS_LABEL 1019
#define IDC_ADD_EGG 1021
#define IDC_EDIT_EGG 1022
#define IDC_REMOVE_EGG 1023
#define IDC_LIST_EGGS 1024
#define IDC_OVERWRITE_CHECK 1027
#define IDC_EXPORT 1028
#define IDC_PANEL_TITLE 1029
#define IDC_OVERWRITE_CHECK2 1030
#define IDC_PVIEW_CHECK 1030
#define IDC_MODEL 1033
#define IDC_ANIMATION 1034
#define IDC_BOTH 1035
#define IDC_POSE 1036
#define IDC_FILENAME 1038
#define IDC_BROWSE 1039
#define IDC_EXPORT_ALL 1040
#define IDC_EXPORT_SELECTED 1041
#define IDC_ADD_EXPORT 1043
#define IDC_LIST_EXPORT 1044
#define IDC_REMOVE_EXPORT 1046
#define IDC_EXP_ALL_FRAMES 1049
#define IDC_EXP_SEL_FRAMES 1050
#define IDC_SF 1051
#define IDC_SF_LABEL 1052
#define IDC_EF 1053
#define IDC_CHECK1 1054
#define IDC_EF_LABEL 1057
#define IDC_OK 1058
#define IDC_CANCEL 1059
#define IDC_LOGGING 1060
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1061
#define _APS_NEXT_SYMED_VALUE 102
#endif
#endif