• <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坐標(biāo)變換的討論 【繪圖類封裝、多線程繪圖和優(yōu)化處理(1)】

            前一篇 說明了最基本的繪圖封裝eArtist類,這一篇通過探討坐標(biāo)變換說明使用方法,重點在說明eArtist坐標(biāo)變換容易讓人迷惑的地方,但是這個類的函數(shù)這樣設(shè)計是有原因的,或許有更好的實現(xiàn)來避免這些迷惑。
            首先寫一個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 }
            響應(yīng)WM_SIZE消息,改變RenderTarget的大小,實際上不改變他的大小也是沒有任何問題的,因為DirectX會自動根據(jù)新窗口大小按比例縮放。這里我們還是讓他改變
            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 }
            在響應(yīng)WM_PAINT消息時,調(diào)用Render()函數(shù),我們在這個函數(shù)中展示坐標(biāo)變換的用法。
            D2D1_MATRIX_3X2_F 是一個3X2的矩陣,其中前2X2方陣是坐標(biāo)變換方陣,可以完成旋轉(zhuǎn)和縮放,第3行的兩個點是原點的平移位置。這些內(nèi)容可以參考任何線性代數(shù)書,計算機繪圖書或游戲開發(fā)材料,在此不多說了。
            下面這個函數(shù)用三種顏色分段畫了一條從左上角到右下角的直線,如下圖:

            代碼如下:注意畫出三個線段的代碼是同樣的,由于坐標(biāo)原點平移了,劃線的位置也不同。
             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     //設(shè)定坐標(biāo)變換為單位矩陣
            11     _artist->SetTransform(&m);
            12     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(02550)));
            13     //畫出第一段
            14     _artist->DrawLine(00, width, height);
            15 
            16     //設(shè)定坐標(biāo)原點的平移
            17     m._31 = _rectClient.right/3, m._32 = _rectClient.bottom / 3;
            18     _artist->SetTransform(&m);
            19     //設(shè)定藍色線段
            20     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(25500)));
            21     //同樣的代碼畫出第二段
            22     _artist->DrawLine(00, width, height);
            23 
            24     
            25     //設(shè)定坐標(biāo)原點的平移
            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的兼容格式一般也設(shè)定為BGRA,A是alpha透明度。具體的可以看微軟圖像兼容格式規(guī)格文檔。
            容易混淆的地方在于,如果屏幕上的圖形有很多部分,每部分用到了不同的變換,對于一個智商低下的我來說,很容易搞亂

            第一種辦法是在單線程繪圖中先對原來的變換作個備份,用完之后再恢復(fù):
            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是獨立的,對他的變換設(shè)定不會影響到其他線程,首先按照微軟的建議,在CTestDx2d中添加一個ID2D1Bitmap *_bmp_screen,這個位圖資源在初始時被創(chuàng)建,大小為窗口客戶區(qū)大小,把這句話加到OnSize函數(shù)中就可以使用了,并且不要忘記在~CTestDx2d中釋放資源:

            1 _artist->CreateBitmap(&_bmp_screen, _rectClient);
            CreateBitmap的內(nèi)部實現(xiàn)是這樣的:
            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 }
            先釋放現(xiàn)有的位圖資源,然后創(chuàng)建了BGRA格式的位圖。Again, 位圖創(chuàng)建后應(yīng)盡量重復(fù)使用,直到程序退出再釋放。
            現(xiàn)在用Bitmap-RenderTarget畫第三個線段,用一個小矩形標(biāo)出Bmp-RT繪制的區(qū)域:


            第18行使用了Bitmap-RT繪圖,注意所有的坐標(biāo)還是從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
                //設(shè)定坐標(biāo)原點的平移
            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     //注意坐標(biāo)原點是從0,0開始的,說明Bitmap-RT已經(jīng)繼承了來自Hwnd-RT的坐標(biāo)變換
            23     _artist->DrawLine(00, width, height);
            24 
            25     //畫一個矩形以清楚的表明Bitmap的位置
            26     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(255255255)));
            27     _artist->DrawRectangle(00, width, height);
            28 
            29     //結(jié)束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
                //設(shè)定坐標(biāo)原點的平移
            16     m._31 = _rectClient.right * 2 /3, m._32 = _rectClient.bottom * 2/ 3;
            17     _artist->SetTransform(&m);
            注意BeginBmpDraw在SetTransfor之前,這樣就是給Bmp-RT設(shè)定坐標(biāo)變換,如果這兩句反過來寫,就是給Hwnd-RT設(shè)定變換,在這個例子中,這兩者的效果是一樣的,但是如果想在Bmp-RT中再畫一條線小矩形區(qū)域外的線,就會在錯誤的地方畫一條先,甚至產(chǎn)生種種讓人迷惑費解的效果,原因就是設(shè)定了不同的RenderTarget。或者可以在設(shè)定坐標(biāo)變換之前顯示的使用UsingBmpRT(),然后再設(shè)定坐標(biāo)。這是非常容易誤解的地方。

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

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


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            <2012年12月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            留言簿(3)

            隨筆檔案

            相冊

            contact

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            性高湖久久久久久久久AAAAA| 亚洲一区二区三区日本久久九| 久久人妻少妇嫩草AV蜜桃| 久久精品中文字幕有码| 伊人久久大香线蕉精品不卡| 中文成人无码精品久久久不卡| 欧美精品久久久久久久自慰| 99久久99久久精品国产| 日韩人妻无码一区二区三区久久99| 久久九九精品99国产精品| 久久久亚洲精品蜜桃臀| 精品久久久久久亚洲精品| 久久亚洲国产最新网站| 亚洲国产精品久久久久网站| 色老头网站久久网| 免费观看久久精彩视频| 无码日韩人妻精品久久蜜桃| 久久久久久无码国产精品中文字幕| 日韩人妻无码精品久久免费一| 国产成人综合久久久久久| 久久精品国产亚洲av水果派| 久久久久亚洲AV成人网人人网站| 久久综合综合久久97色| 精品人妻久久久久久888| 亚洲日本va中文字幕久久| 久久久久亚洲av成人无码电影 | 69久久夜色精品国产69| 亚洲国产成人久久综合碰| 亚洲精品国产成人99久久| 99久久精品午夜一区二区| 亚洲AV无一区二区三区久久| 久久国产劲爆AV内射—百度| 思思久久99热免费精品6| 久久久久免费精品国产| 久久大香香蕉国产| 天堂久久天堂AV色综合| 亚洲综合伊人久久综合| 热99RE久久精品这里都是精品免费| 久久久WWW成人免费毛片| 色综合久久天天综合| 久久精品国产一区二区电影|