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

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

            代碼如下:注意畫(huà)出三個(gè)線段的代碼是同樣的,由于坐標(biāo)原點(diǎn)平移了,劃線的位置也不同。
             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     //畫(huà)出第一段
            14     _artist->DrawLine(00, width, height);
            15 
            16     //設(shè)定坐標(biāo)原點(diǎn)的平移
            17     m._31 = _rectClient.right/3, m._32 = _rectClient.bottom / 3;
            18     _artist->SetTransform(&m);
            19     //設(shè)定藍(lán)色線段
            20     _artist->SetSolidColorBrush(D2D1::ColorF(BGR(25500)));
            21     //同樣的代碼畫(huà)出第二段
            22     _artist->DrawLine(00, width, height);
            23 
            24     
            25     //設(shè)定坐標(biāo)原點(diǎn)的平移
            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     //同樣的代碼畫(huà)出第三段
            31     _artist->DrawLine(00, width, height);
            32
            33     _artist->EndDraw();
            34 }
            宏BGR按照blue, green, red的順序定義顏色,這與一般使用的RGB定義順序不同,是因?yàn)檫@樣的順序能獲得更好的性能,RenderTarget的兼容格式一般也設(shè)定為BGRA,A是alpha透明度。具體的可以看微軟圖像兼容格式規(guī)格文檔。
            容易混淆的地方在于,如果屏幕上的圖形有很多部分,每部分用到了不同的變換,對(duì)于一個(gè)智商低下的我來(lái)說(shuō),很容易搞亂

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

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

            1 _artist->CreateBitmap(&_bmp_screen, _rectClient);
            CreateBitmap的內(nèi)部實(shí)現(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畫(huà)第三個(gè)線段,用一個(gè)小矩形標(biāo)出Bmp-RT繪制的區(qū)域:


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

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

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


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


            <2025年6月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(3)

            隨筆檔案

            相冊(cè)

            contact

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久精品国产亚洲AV香蕉| 99久久人妻无码精品系列蜜桃| 亚洲精品无码久久千人斩| 亚洲国产高清精品线久久| 国产综合免费精品久久久| 国产亚洲色婷婷久久99精品91| 国产午夜福利精品久久2021 | 国内精品久久久久久中文字幕 | 久久精品国产99久久久古代| 久久人人爽人人爽人人片AV高清 | 99久久亚洲综合精品成人| 久久性精品| 国产精品久久久久久| 久久久久亚洲AV综合波多野结衣 | 18岁日韩内射颜射午夜久久成人| 国产精品久久久久久福利漫画| 久久久久九九精品影院| 久久久噜噜噜久久熟女AA片| 精品久久久久久无码免费| 99久久久精品免费观看国产| 一本久久a久久精品综合香蕉| 成人资源影音先锋久久资源网| 久久天天躁夜夜躁狠狠| 久久强奷乱码老熟女| 岛国搬运www久久| 国产精品久久久久久影院| 精品国产VA久久久久久久冰| 色婷婷综合久久久中文字幕 | 久久综合久久综合久久综合| 亚洲精品美女久久久久99| 久久综合视频网| 久久亚洲国产成人影院| 久久久噜噜噜久久| 欧美成a人片免费看久久| 久久99久久无码毛片一区二区| 国产精品久久国产精品99盘| 国产日产久久高清欧美一区| 国产一区二区三区久久精品| 久久九九青青国产精品| 亚洲国产精品久久久久婷婷软件| 国产精品久久久久久福利漫画 |