• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            WarmGUI(3-1) 對DirectX2D坐標變換的討論 【繪圖類封裝、多線程繪圖和優化處理(1)】

            前一篇 說明了最基本的繪圖封裝eArtist類,這一篇通過探討坐標變換說明使用方法,重點在說明eArtist坐標變換容易讓人迷惑的地方,但是這個類的函數這樣設計是有原因的,或許有更好的實現來避免這些迷惑。
            首先寫一個class CTestDx2d幫助窗體完成繪圖
             1 class CTestDx2d
             2 {
             3 public:
             4     CTestDx2d(void);
             5     ~CTestDx2d(void);
             6 
             7     int  OnCreate(HWND hwnd);    
             8     void OnSize(int cx, int cy);
             9     void Render();
            10 
            11 protected:
            12     HWND _hwnd;                   ///保存窗口句柄
            13     WARMGUI::eArtist* _artist; ///i am Artist!
            14     RECT _rectClient;          ///窗口大小
            15 };
            在WM_CREATE消息時,初始化_artist
             1 int CTestDx2d::OnCreate(HWND hwnd)
             2 {
             3     _hwnd = hwnd;
             4 
             5     //create render target
             6     CDxFactorys::GetInstance()->CreateRenderTarget(_hwnd, &_pHwndRT);
             7     _artist = new WARMGUI::eArtist();
             8     _artist->Init(_hwnd);
             9 
            10     return (0);
            11 }
            響應WM_SIZE消息,改變RenderTarget的大小,實際上不改變他的大小也是沒有任何問題的,因為DirectX會自動根據新窗口大小按比例縮放。這里我們還是讓他改變
            1 void CTestDx2d::OnSize(int cx, int cy)
            2 {
            3     _rectClient.left = _rectClient.top = 0, _rectClient.right = cx, _rectClient.bottom = cy;
            4     _artist->ResizeRenderTarget(cx, cy);
            5 }
            在響應WM_PAINT消息時,調用Render()函數,我們在這個函數中展示坐標變換的用法。
            D2D1_MATRIX_3X2_F 是一個3X2的矩陣,其中前2X2方陣是坐標變換方陣,可以完成旋轉和縮放,第3行的兩個點是原點的平移位置。這些內容可以參考任何線性代數書,計算機繪圖書或游戲開發材料,在此不多說了。
            下面這個函數用三種顏色分段畫了一條從左上角到右下角的直線,如下圖:

            代碼如下:注意畫出三個線段的代碼是同樣的,由于坐標原點平移了,劃線的位置也不同。
             1 #define BGR(b,g,r) ((COLORREF)(((BYTE)(b)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(r))<<16)))
             2 
             3 void CTestDx2d::_test_trns()
             4 {
             5     int width = _rectClient.right / 3, height = _rectClient.bottom / 3;
             6 
             7     D2D1_MATRIX_3X2_F m = D2D1::Matrix3x2F::Identity();
             8     _artist->BeginDraw(true);
             9 
            10     //設定坐標變換為單位矩陣
            11     _artist->SetTransform(&m);
            12     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(02550)));
            13     //畫出第一段
            14     _artist->DrawLine(00, width, height);
            15 
            16     //設定坐標原點的平移
            17     m._31 = _rectClient.right/3, m._32 = _rectClient.bottom / 3;
            18     _artist->SetTransform(&m);
            19     //設定藍色線段
            20     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(25500)));
            21     //同樣的代碼畫出第二段
            22     _artist->DrawLine(00, width, height);
            23 
            24     
            25     //設定坐標原點的平移
            26     m._31 = _rectClient.right * 2 /3, m._32 = _rectClient.bottom * 2/ 3;
            27     _artist->SetTransform(&m);
            28     //紅色線段
            29     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(00255)));
            30     //同樣的代碼畫出第三段
            31     _artist->DrawLine(00, width, height);
            32
            33     _artist->EndDraw();
            34 }
            宏BGR按照blue, green, red的順序定義顏色,這與一般使用的RGB定義順序不同,是因為這樣的順序能獲得更好的性能,RenderTarget的兼容格式一般也設定為BGRA,A是alpha透明度。具體的可以看微軟圖像兼容格式規格文檔。
            容易混淆的地方在于,如果屏幕上的圖形有很多部分,每部分用到了不同的變換,對于一個智商低下的我來說,很容易搞亂

            第一種辦法是在單線程繪圖中先對原來的變換作個備份,用完之后再恢復:
            1 ID2D1_MATRIX_3X2_F mOld, mNew;
            2 _artist->GetTransform(&mOld;)
            3 _artist->SetTransform(&mNew;)
            4 
            5 DrawSomething();
            6 
            7 _artist->SetTransform(&mOld;)

            如果有多個線程同時使用,用互斥鎖又等于把多線程繪圖變成了單線程繪圖,因此第二個方法是使用Bitmap-RT繪圖,然后再從Bitmap-RT繪制到Hwnd-RT.由于每個Bitmap-RT是獨立的,對他的變換設定不會影響到其他線程,首先按照微軟的建議,在CTestDx2d中添加一個ID2D1Bitmap *_bmp_screen,這個位圖資源在初始時被創建,大小為窗口客戶區大小,把這句話加到OnSize函數中就可以使用了,并且不要忘記在~CTestDx2d中釋放資源:

            1 _artist->CreateBitmap(&_bmp_screen, _rectClient);
            CreateBitmap的內部實現是這樣的:
            1 inline HRESULT eArtist::CreateBitmap(WGBitmap** pBitmap, RECT& rect)
            2 {
            3     SafeRelease(pBitmap);
            4     return _pHwndRT->CreateBitmap(
            5                 D2D1::SizeU(RectWidth(rect), RectHeight(rect)),
            6                 D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)),
            7                 pBitmap);
            8 }
            先釋放現有的位圖資源,然后創建了BGRA格式的位圖。Again, 位圖創建后應盡量重復使用,直到程序退出再釋放。
            現在用Bitmap-RenderTarget畫第三個線段,用一個小矩形標出Bmp-RT繪制的區域:


            第18行使用了Bitmap-RT繪圖,注意所有的坐標還是從0,0開始的
             1 void CTestDx2d::Render()
             2 {
             3     int width = _rectClient.right / 3, height = _rectClient.bottom / 3;
             4 
             5     MATRIX_2D_t m = D2D1::Matrix3x2F::Identity();
             6     _artist->BeginDraw(true);
             7 
             8     //
             9     //畫前兩段的代碼同上
            10     //
            11 
            12     //畫第三段
            13     //使用Bitmap-RenderTarget畫圖
            14     _artist->BeginBmpDraw();
            15
                //設定坐標原點的平移
            16     m._31 = _rectClient.right * 2 /3, m._32 = _rectClient.bottom * 2/ 3;
            17     _artist->SetTransform(&m);
            18
            19     //紅色線段
            20     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(00255)));
            21     //同樣的代碼畫出第三段
            22     //注意坐標原點是從0,0開始的,說明Bitmap-RT已經繼承了來自Hwnd-RT的坐標變換
            23     _artist->DrawLine(00, width, height);
            24 
            25     //畫一個矩形以清楚的表明Bitmap的位置
            26     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(255255255)));
            27     _artist->DrawRectangle(00, width, height);
            28 
            29     //結束Bmp-RT畫圖
            30     _artist->EndBmpDraw();
            31 
            32     //從Bitmap-RenderTarget上獲得位圖
            33     POINT p0 = {00};
            34     RECT rect = {00, width, height};
            35     _artist->CopyFromRenderTarget(_bmp_screen, p0, rect);
            36 
            37     //繪制位圖
            38     _artist->UsingHwndRT();
            39     _artist->DrawBitmap(_bmp_screen, rect, rect);
            40 
            41     _artist->EndDraw();
            42 }

            看這幾句話,
            12     //畫第三段
            13     //使用Bitmap-RenderTarget畫圖
            14     _artist->BeginBmpDraw();
            15
                //設定坐標原點的平移
            16     m._31 = _rectClient.right * 2 /3, m._32 = _rectClient.bottom * 2/ 3;
            17     _artist->SetTransform(&m);
            注意BeginBmpDraw在SetTransfor之前,這樣就是給Bmp-RT設定坐標變換,如果這兩句反過來寫,就是給Hwnd-RT設定變換,在這個例子中,這兩者的效果是一樣的,但是如果想在Bmp-RT中再畫一條線小矩形區域外的線,就會在錯誤的地方畫一條先,甚至產生種種讓人迷惑費解的效果,原因就是設定了不同的RenderTarget?;蛘呖梢栽谠O定坐標變換之前顯示的使用UsingBmpRT(),然后再設定坐標。這是非常容易誤解的地方。

            但這么設計是有原因的,原因在于繪圖的函數可以寫的很簡單,比如_artist->DrawLine(),可以不同繪圖策略中使用同樣的代碼繪制圖形,圖形被繪制到了不同的RenderTarget上,所以要小心的使用坐標變換,確保正確。實踐中,盡可能保持HwndRT的變換始終為單位矩陣,變換更多的在BmpRT中做。如果是多線程繪圖更應該使用這樣的方法。

            posted on 2012-12-15 16:26 畢達哥拉斯半圓 閱讀(1726) 評論(0)  編輯 收藏 引用

            <2012年9月>
            2627282930311
            2345678
            9101112131415
            16171819202122
            23242526272829
            30123456

            導航

            統計

            常用鏈接

            留言簿(3)

            隨筆檔案

            相冊

            contact

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久九九青青国产精品| 久久九色综合九色99伊人| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 一本色道久久HEZYO无码| 亚洲综合精品香蕉久久网| 色欲综合久久中文字幕网| 久久久久久无码国产精品中文字幕| 久久福利片| 久久久九九有精品国产| 人妻无码久久精品| 精品国产青草久久久久福利| 要久久爱在线免费观看| 久久亚洲春色中文字幕久久久| 欧美亚洲日本久久精品| 久久这里只有精品18| 久久久久综合国产欧美一区二区 | 久久婷婷色综合一区二区| 人妻精品久久无码区| 亚洲国产高清精品线久久| 爱做久久久久久| 久久久久黑人强伦姧人妻| 69久久夜色精品国产69| 久久亚洲AV成人出白浆无码国产 | 伊人色综合久久天天| 久久精品www| 国产福利电影一区二区三区久久老子无码午夜伦不 | 精品久久久久香蕉网| 国产精品视频久久| 伊人久久综合精品无码AV专区| 久久久久99精品成人片| 99久久精品国产一区二区蜜芽| 国产成人无码久久久精品一| 久久国语露脸国产精品电影| 婷婷五月深深久久精品| 伊人久久大香线蕉综合影院首页| 欧美精品九九99久久在观看| 婷婷久久五月天| 久久综合色老色| 日韩欧美亚洲综合久久| 精品久久久久久综合日本| 久久99热狠狠色精品一区|