2010年1月12日 星期二

3dsMax Exporter Plug-in (3)

Well, 我們的Exporter還沒做完。

我們在MyExporter1::DoExport設定中斷點,會發現,這個函式會在我們選定了輸出檔,按下存檔之後才被呼叫。這時候,就開始了輸出工作。

首先會看到一個對話盒。

DoExport的程式碼裡,也就呼叫這個對話盒而已,實際輸出工作的呼叫,還是得要我們自己來。

clip_image001

這個對話盒是project wizard幫我們建立的,專案裡面有一個rc檔,我們可以打開來自己改。

例如,改成這樣,

clip_image002

我們可以將輸出時候需要的設定與選項,放在這對話盒裡頭,使用者按下了OK,實際的輸出工作就會開始進行了。

接下來,我們真的要開始從Max抓資料了。

Max有SDK,SDK也有Help文件。但是我們看習慣了MSDN, DirectX SDK文件之後,會發現Max SDK的文件真的是弄得很糟糕。但是我們還是得看。

有總比沒有好。

為了讓程式碼結構清晰些,我們建立一個ExporterPipeline物件來做這一堆苦工。

class CExporterPipeline
{
public:
    CExporterPipeline();
    ~CExporterPipeline();
    HRESULT Create(const char* model_name,const ExporterParameters& param);
    void SyncData();
    HRESULT Destroy();
private:
    void BeginSync();
    void EndSync();
    void SyncScene();
    void SyncGameNodeTree(int level,IGameNode* node,IGameNode* parent_node);
    void SyncGameNode(int level, IGameNode* node,IGameNode* parent_node);
    void SyncGameNodeGameObject(IGameNode* node, IGameObject* go);
    void SyncGameNodeMesh(IGameNode* node, IGameMesh* gm);
    void SyncGameNodeMaterial(IGameNode* node);
    void SyncGeometryData(IGameNode* node,IGameMesh* gm);
    void SyncMaterial(IGameNode* node, int matid, Mtl* mtl);
    void UpdateMeshSkinVertex(IGameNode* node,IGameMesh* gm);
    void UpdateNodeFrameAnimation(IGameNode* node);
private:
    Interface* m_MaxCore;
    IGameScene* m_Scene;
    IGameConversionManager* m_ConversionMgr;
    FILE* m_fpExportFile;
    ExporterParameters m_ExportParameters;
    int m_nTotalNodeCount;
    int m_nProgressNodeCount;
    std::vector<int> m_GameNodeIDArray;
};
extern CExporterPipeline g_ExporterPipeline;

ExporterPipeline只有幾個public函式: Create, SyncData, Destroy。其餘的苦工全部寫在private函式裡。

我們在MyExporter1::DoExport裡面這樣呼叫 :

int    MyExporter1::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options)
{
    #pragma message(TODO("Implement the actual file Export here and"))
    if(!suppressPrompts)
        DialogBoxParam(hInstance,
                MAKEINTRESOURCE(IDD_PANEL),
                GetActiveWindow(),
                MyExporter1OptionsDlgProc, (LPARAM)this);
    ExporterParameters params;
    g_ExporterPipeline.Create(name,params);
    g_ExporterPipeline.SyncData();
    g_ExporterPipeline.Destroy();
    #pragma message(TODO("return TRUE If the file is exported properly"))
    return FALSE;
}

Create建立需要的物件與檔案,SyncData處理資料輸出,Destroy清除物件以及關閉檔案。

大致上外部的步驟就這樣。細節都藏在Exporter Pipeline裡,下回再繼續吧...

沒有留言: