mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-17 20:23:47 -04:00
577 lines
18 KiB
C++
Executable File
577 lines
18 KiB
C++
Executable File
/*
|
|
MaxEgg.cpp
|
|
Created by Steven "Sauce" Osman, 01/??/03
|
|
odified and maintained by Ken Strickland, (02/25/03)-(Present)
|
|
Carnegie Mellon University, Entetainment Technology Center
|
|
|
|
This file implements the classes that are used in the Panda 3D file
|
|
exporter for 3D Studio Max.
|
|
*/
|
|
|
|
// Discreet-Generated ID for this app.
|
|
#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 am a helper object!"
|
|
*/
|
|
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 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"); }
|
|
};
|
|
|
|
// Our private global instance of the above class
|
|
static MaxEggPluginClassDesc 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 )
|
|
{
|
|
MaxOptionsDialog *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)
|
|
{
|
|
// 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);
|
|
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 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 MaxOptionsDialog();
|
|
tempEgg->SetMaxInterface(imp->iObjParams);
|
|
tempEgg->SetAnimRange();
|
|
res = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EGG_DETAILS),
|
|
hWnd, MaxOptionsDialogProc, (LPARAM)tempEgg);
|
|
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) {
|
|
MaxOptionsDialog *tempEgg = imp->GetEgg(sel);
|
|
if (tempEgg) {
|
|
tempEgg->SetAnimRange();
|
|
tempEgg->CullBadNodes();
|
|
DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EGG_DETAILS),
|
|
hWnd, MaxOptionsDialogProc, (LPARAM)tempEgg);
|
|
}
|
|
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::MaxEggPlugin() :
|
|
autoOverwrite(false), pview(true), logOutput(false), numEggs(0), maxEggs(5)
|
|
{
|
|
eggList = new MaxOptionsDialog*[maxEggs];
|
|
BuildMesh();
|
|
}
|
|
|
|
MaxEggPlugin::~MaxEggPlugin() {
|
|
for (int i = 0; i < numEggs; i++) delete eggList[i];
|
|
delete [] eggList;
|
|
}
|
|
|
|
void MaxEggPlugin::AddEgg(MaxOptionsDialog *newEgg) {
|
|
if (numEggs >= maxEggs) {
|
|
MaxOptionsDialog **newList;
|
|
maxEggs *= 2;
|
|
newList = new MaxOptionsDialog*[maxEggs];
|
|
for (int i = 0; i < numEggs; i++) newList[i] = eggList[i];
|
|
delete [] eggList;
|
|
eggList = newList;
|
|
}
|
|
|
|
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;
|
|
for (int i=0; i<numEggs; i++) {
|
|
eggList[i]->SetMaxInterface(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 );
|
|
}
|
|
}
|
|
|
|
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]->_short_name;
|
|
ListView_InsertItem(lv, &Item);
|
|
Item.iSubItem = 1;
|
|
switch(eggList[i]->_anim_type) {
|
|
case MaxEggOptions::AT_chan: Item.pszText = "Animation"; break;
|
|
case MaxEggOptions::AT_both: Item.pszText = "Both"; break;
|
|
case MaxEggOptions::AT_pose: Item.pszText = "Pose"; break;
|
|
case MaxEggOptions::AT_model: Item.pszText = "Model"; break;
|
|
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;
|
|
|
|
std::stringstream status;
|
|
|
|
SaveCheckState();
|
|
|
|
for (int i = 0; i < numEggs; i++) {
|
|
if (eggList[i]->_checked) {
|
|
MaxToEggConverter converter;
|
|
if (converter.convert((MaxEggOptions*)eggList[i])) {
|
|
good += 1;
|
|
status << "Successfully created " << eggList[i]->_short_name << ".egg\n";
|
|
} else {
|
|
bad += 1;
|
|
status << "Could not export " << eggList[i]->_short_name << ".egg\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT mask = MB_OK;
|
|
if (bad > 0) mask |= MB_ICONEXCLAMATION;
|
|
else mask |= MB_ICONINFORMATION;
|
|
|
|
MessageBox(hMaxEggParams, status.str().c_str(), "Panda3D Export results", mask);
|
|
|
|
int pviewed = 0;
|
|
if (pview && good > 0) {
|
|
for (i = 0; i < numEggs; i++) {
|
|
if (eggList[i]->_checked && eggList[i]->_successful) {
|
|
if (eggList[i]->_anim_type != MaxEggOptions::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]->_short_name);
|
|
char cmdLine[2048];
|
|
sprintf(cmdLine, "pview \"%s\"", eggList[i]->_file_name);
|
|
CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
|
|
NULL, NULL, &si, &pi);
|
|
pviewed += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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();
|
|
MaxOptionsDialog *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 MaxOptionsDialog();
|
|
temp->SetMaxInterface(iObjParams);
|
|
temp->Load(iload);
|
|
AddEgg(temp);
|
|
break;
|
|
}
|
|
iload->CloseChunk();
|
|
res = iload->OpenChunk();
|
|
}
|
|
|
|
return IO_OK;
|
|
}
|
|
|
|
/**********************************************************************
|
|
*
|
|
* DLL Initialization
|
|
*
|
|
**********************************************************************/
|
|
|
|
extern ClassDesc* GetMaxEggPluginDesc();
|
|
|
|
HINSTANCE hInstance;
|
|
int controlsInit = FALSE;
|
|
|
|
// This function is called by Windows when the DLL is loaded. This
|
|
// function may also be called many times during time critical operations
|
|
// like rendering. Therefore developers need to be careful what they
|
|
// do inside this function. In the code below, note how after the DLL is
|
|
// loaded the first time only a few statements are executed.
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved)
|
|
{
|
|
hInstance = hinstDLL; // Hang on to this DLL's instance handle.
|
|
|
|
if (!controlsInit) {
|
|
controlsInit = TRUE;
|
|
InitCustomControls(hInstance); // Initialize MAX's custom controls
|
|
InitCommonControls(); // Initialize Win95 controls
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
// This function returns a string that describes the DLL and where the user
|
|
// could purchase the DLL if they don't have it.
|
|
__declspec( dllexport ) const TCHAR* LibDescription()
|
|
{
|
|
return GetString(IDS_LIBDESCRIPTION);
|
|
}
|
|
|
|
// This function returns the number of plug-in classes this DLL operates on.
|
|
//TODO: Must change this number when adding a new class
|
|
__declspec( dllexport ) int LibNumberClasses()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// This function returns the descriptions of the plug-in classes this DLL operates on.
|
|
__declspec( dllexport ) ClassDesc* LibClassDesc(int i)
|
|
{
|
|
switch(i) {
|
|
case 0: return GetMaxEggPluginDesc();
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
// This function returns a pre-defined constant indicating the version of
|
|
// the system under which it was compiled. It is used to allow the system
|
|
// to catch obsolete DLLs.
|
|
__declspec( dllexport ) ULONG LibVersion()
|
|
{
|
|
return VERSION_3DSMAX;
|
|
}
|
|
|
|
TCHAR *GetString(int id)
|
|
{
|
|
static TCHAR buf[256];
|
|
|
|
if (hInstance)
|
|
return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL;
|
|
return NULL;
|
|
}
|
|
|