2010年1月25日 星期一

Multi-Thread Debugger

前幾天,下載了Visual Studio 2010 Beta版來安裝,人家問,有什麼新功能值得裝來的呀?

我也不知道。

回頭看了一看,有些附加功能 -- 效能分析、單元測試、程式碼靜態分析....好像都提不起勁....

然後是這個 – Multi-Thread Debugger。

啊....發現好東西....

Multi-Thread的時代,一定要有Multi-Thread 的Debugger啊!!

趕快開了個Multi-Thread的專案來測試。

未命名vs10_thread

當我在主緒中斷的時候,左邊的這個Thread視窗,會列出執行中的執行緒,在執行緒上點擊兩下,就會跳到所選擇的執行緒上,右邊視窗就可以看到這個執行緒的Call Stack,同時也可以知道變數的數值。

於是,多個執行緒的狀況可以同時掌握,對多緒程式的除錯真是一大福音啊....

VS 2010還有一個Parallel Stacks的視窗。不過我還看不出來它的用途。

未命名vs10_call_stack

VS 2008好像也有多緒除錯的功能,不過說實話,VS 2008沒有去詳細探究。畢竟人家說,VS 2008跟Vista一樣是個失敗品啊...

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裡,下回再繼續吧...