• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 淺談位圖的淡入淡出和漸隱

    發表于:2007-07-14來源:作者:點擊數: 標簽:
    成都電子科技大學朱寧 在許多 游戲 和屏幕保護程序中,我們都可以發現位圖的淡入淡出和漸隱(一幅圖象漸漸的消失于另一幅圖象中)的應用。如何實現這些效果呢? 在 windows (GDI)環境下,實現位圖的淡入淡出和漸隱的方法有三種:1.調色板動畫;2.模式畫刷;3
    成都電子科技大學   朱寧

    在許多游戲和屏幕保護程序中,我們都可以發現位圖的淡入淡出和漸隱(一幅圖象漸漸的消失于另一幅圖象中)的應用。如何實現這些效果呢?

    windows(GDI)環境下,實現位圖的淡入淡出和漸隱的方法有三種:1.調色板動畫;2.模式畫刷;3.動畫法。其中,第一種方法速度很快,但只能用于256色的圖形,而且不易實現漸隱效果。第二種方法實現比較簡單,但是主觀效果不及其余兩種。第三種方法的效果很好,但速度要稍慢一些。由于現在已經很難得到質量較高的256色圖片,加之目前幾乎所有的顯卡均支持高彩和真彩模式,所以不推薦采用第一種方法。下面介紹后兩種方法在Visual C++編程環境下的實現。



    一:模式畫刷法:

    CDC類的BitBlt(...),MaskBlt(...),以及WIN32API ::StretchDIBits(...)函數均支持三元ROP(Raster Operation)操作,即由源,模式畫刷(pattern brush)和目的區域原有的圖形經一定的邏輯運算而形成最終的輸出圖形。所以,通過改變模式畫刷的圖案,輔以一定的ROP操作,就可以形成一些特殊的效果。

    首先,要準備若干個8*8的單色位圖,作為模式畫刷的模板。單色位圖中應只含有黑白兩種顏色的像素,每一個位圖中兩種像素的比例和形狀將決定顯示的效果,通常我們由一個全黑的位圖開始,逐漸增加白色像素的比例,最后一幅位圖全部由白色象素組成。

    這些位圖制作好以后,將它們Import入工程,命名為IDB_PATTERN1、IDB_PATTERN2 ... ... 調用CBitmap::LoadBitmap(...)函數將其選入對應的CBitmap對象,然后調用CBrush::CreatePatternBrush(...)制作模式畫刷。

    有了合適的模式畫刷以后,還需要設定我們所需的ROP碼,對于淡入操作,要求將源位圖與模式畫刷的反依次相與。對于淡出操作,要求將當前顯示區域的位圖與模式畫刷依次相與。對于漸隱,我們需要把原位圖與模式畫刷相與后,把這個結果和當前顯示區域的位圖和畫刷的鏡象(原畫刷的非)相與的結果相或。依次改變畫刷,就可以得到漸隱的效果。這些操作的ROP碼,MFC中并沒有對應的預定義宏,但我們可以通過計算得到它,在Visual C++ 5.0 的在線文檔“Ternary Raster Operations”中,詳細介紹了計算方法。最終我們得到淡入、淡出操作的ROP碼分別為000C0324、0x00A000C9。漸隱操作的ROP碼是0x00AC0744。為了形成完整的動畫效果,我們需要設置一個定時器來自動的執行這一系列的操作。

    下面用一個簡單的例子說明模式畫刷法的實現:



    1:建立一個基于對話框的項目,命名為PatternDemo.

    2:刪除對話框上的“Todo:...”注釋,并增加一個按紐,命名為“DEMO”

    3:為DEMO按紐加入對應的事件句柄OnDEMO(...).

    4:在CPatternDemo中加入私有成員變量如下:

    CDC *pdc;

    CDC memDC;

    CBitmap bmp;

    CBrush brush[8];

    UINT counter;

    UINT mode;

    UINT onrun;

    5:用VC自帶的位圖編輯器,按上文要求編輯8個8*8像素的單色位圖,命名為IDB_PATTERN1...IDB_PATTERN8。

    6:Import兩個100*100像素的真彩bmp圖片,命名為IDB_BMPSOURCE1和IDB_BMPSOURCE2。

    7:使用ClassWizard為CPatternDemoDlg加入WM_CREATE的消息響應函數OnCreate(...),并在其中添加如下代碼:

    ...

    for(int i=0;i<8;i++)

        {

        bmp.LoadBitmap(IDB_PATTERN1+i);

        brush[i].CreatePatternBrush(&bmp);

        bmp.DeleteObject();

        }

    ...

    8:在CPatternDemoDlg::OnDEMO(...)函數中添加如下代碼:

    ...

        if(!onrun)

    {

    pdc=GetDC();

    pdc->SetBkColor(RGB(0,0,0));

    pdc->SetTextColor(RGB(255,255,255));

    pdc->FillSolidRect(0,0,100,100,RGB(0,0,0));

    memDC.CreateCompatibleDC(pdc);

    bmp.LoadBitmap(IDB_BMPSOURCE1);

    memDC.SelectObject(&bmp);

    bmp.DeleteObject();

    mode=1;

    counter=0;

    SetTimer(1,200,NULL);

    onrun=1;

    }

    ...

    9:使用ClassWizard為CPatternDemoDlg加入WM_TIMER的消息響應函數OnTimer(...),并在其中添加如下代碼:

    ...

    if(mode==1)

    {

        if(counter>7)

        {

        mode=2;

        counter=0;

        return;

        }

        pdc->SelectObject(&brush[counter]);

        pdc->BitBlt(0,0,100,100,&memDC,0,0,0x000C0324);

        counter++;

    }



    if(mode==2)

    {

        if(counter>7)

        {

        mode=3;

        counter=0;

        return;

        }

    if(counter==0)

    {

    bmp.LoadBitmap(IDB_BMPSOURCE2);

    memDC.SelectObject(&bmp);

    bmp.DeleteObject();

    }

    pdc->SelectObject(&brush[counter]);

    pdc->BitBlt(0,0,100,100,&memDC,0,0,0x00AC0744);

    counter++;

    }

    if(mode==3)

    {

        if(counter>7)

    {

    memDC.DeleteDC();

    bmp.DeleteObject();

    KillTimer(1);

    onrun=0;

    return;

    }

    pdc->SelectObject(&brush[counter]);

    pdc->BitBlt(0,0,100,100,NULL,0,0,0x00A000C9);

    counter++;

    }

    ...

    9:在CPatternDemoDlg::CpatternDemoDlg()中加入:

    ...

    onrun=0;

    ...

    10: 使用ClassWizard為CPatternDemoDlg加入WM_DESTORY的消息響應函數OnDestory(...),并在其中添加如下代碼:

    ...

    memDC.DeleteDC();

    KillTimer(1);

    ...

    編譯運行該項目,可以看到第一幅圖象從背景中漸漸的浮現出來,隨后,又漸漸地隱入第二幅圖象之中,接著,第二幅圖象又慢慢地消失于背景中。



    動畫法:

        這種方法是利用直接操作位圖的數據來實現的,可以實現像素顏色的平滑變化,視覺效果可以做的很好,因此,這種方法在屏保中的應用非常多。

        首先,我們必須了解bmp圖形的結構。一個bmp圖形由兩個部分組成,即文件頭和數據區,文件頭存放bmp圖形的大小、格式等信息,數據區存放bmp圖形各個像素的顏色信息。對于24位真彩色的bmp來說,文件頭的大小為54個字節,前14個字節對應VC中定義的BITMAPFILEINFO結構,后40個字節對應BITMAPINFOHEADER結構。我們把bmp數據區的數據讀出,經過一定的運算,再利用WIN32API::StretchDIBits(...)函數直接輸出到顯示DC上,就可以實現一些特技效果。



        下面讓我們分步去實現一個全屏幕的演示程序:



    1:生成一個基于對話框的項目,命名為F1:

    2:刪除F1Dlg.h、F1Dlg.h和F1.cpp中與其相關的所有代碼。

    3:在項目中添加一個基類為generic Cwnd的新類,命名為CW.

    4:為CW類添加如下私有成員變量:

    //////////////////////

        UINT y_offset;

        UINT x_offset;

        UINT stage;

        BYTE* p3;

        BYTE * p2;

        BYTE * p1;

        BITMAPINFOHEADER header;

        HGLOBAL hlb1;

        HGLOBAL hlb2;

        HGLOBAL hlb3;

        UINT start;

        UINT counter;

    ////////////////////////

    并在W.h的頂部加入宏定義 #define BMP_SIZE 192000

    5:為CW添加Create(...)虛函數,WM_CREATE,WM_TIMER,WM_PAINT,WM_DESTORY,WM_LBUTTONDOWN的消息句柄,接受缺省的函數名稱。

    6:刪除CW::Create(...)中的原有代碼,用以下代碼替換:

    /////////////////////////

    LPCTSTR m_lpszCN;    

        m_lpszCN = AfxRegisterWndClass(CS_BYTEALIGNCLIENT,

                ::LoadCursor(AfxGetResourceHandle(),

                MAKEINTRESOURCE(IDC_NULLCORSOR)));

        return CWnd::CreateEx(WS_EX_TOPMOST,m_lpszCN, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);

    //////////////////////////

    7: 刪除CF1App:: InitInstance()中#endif以后的所有代碼,用以下代碼代替:

    ///////////////////////////

        int cx=GetSystemMetrics(SM_CXSCREEN);

        int cy=GetSystemMetrics(SM_CYSCREEN);

        CRect rectDefault(0,0,cx,cy);

        m_pMainWnd=new CW();

        m_pMainWnd->Create(NULL, _T("Hello World!"), WS_VISIBLE|WS_POPUP, rectDefault,NULL,NULL);

        return TRUE;

    ///////////////////////////

    8:在CW::OnCreate(...)函數中加入如下代碼:

    /////////////////////////////

        counter=0;   

        int cx=GetSystemMetrics(SM_CXSCREEN);

        int cy=GetSystemMetrics(SM_CYSCREEN);

        x_offset=(cx-640)/2;

        y_offset=(cy-400)/2;

    /////////////////////////////

    9: 在CW::OnDestroy()函數中加入如下代碼:

    ////////////////////////////////

    KillTimer(1);

        GlobalFree(hlb1);

        GlobalFree(hlb2);

        GlobalFree(hlb3);

    /////////////////////////////

    10: 在CW:: OnLButtonDown(...)函數中加入如下代碼:

    //////////////////////////////

        SendMessage(WM_CLOSE);

    //////////////////////////////

    11: 在CW:: OnLButtonDown(...)函數中加入如下代碼:

    /////////////////////////////

    CPaintDC dc(this);

        dc.FillSolidRect(0,0,800,600,RGB(0,0,0));

        dc.SetTextColor(RGB(200,0,0));

        if(!start) return;

        CFile f1,f2;

        f1.Open("bmp1.bmp",CFile::modeRead);

        f2.Open("bmp2.bmp",CFile::modeRead);

        f1.Seek(14,CFile::begin);

        f1.Read(&header,40);

        f2.Seek(54,CFile::begin);

        hlb1=GlobalAlloc(GMEM_MOVEABLE,BMP_SIZE);

        p1=(BYTE*)GlobalLock(hlb1);

        p1=(BYTE*)malloc(BMP_SIZE);

        f1.ReadHuge(p1,BMP_SIZE);

        GlobalUnlock(hlb1);

        hlb2=GlobalAlloc(GMEM_MOVEABLE,BMP_SIZE);

        p2=(BYTE*)GlobalLock(hlb2);

        f2.ReadHuge(p2,BMP_SIZE);

        GlobalUnlock(hlb2);

        hlb3=GlobalAlloc(GMEM_MOVEABLE,BMP_SIZE);

        p3=(BYTE*)GlobalLock(hlb3);

        GlobalUnlock(hlb3);

        f1.Close();

        f2.Close();

        stage=1;

    SetTimer(1,100,NULL);

    start=0;

    ///////////////////////////

    12: 在CW:: OnTimer(...)函數中加入如下代碼:

    ///////////////////////////

    if(stage==1)

        {

        if(counter++>63)

        {

            stage=2;

            counter=0;

            return;

        }

            

        for(int i=0;i<BMP_SIZE;i++)

            p3[i]=counter*p1[i]/64;

            ::StretchDIBits(GetDC()->m_hDC,x_offset,y_offset,640,400,0,0,320,200,p3,

                ((BITMAPINFO*)(&header)),NULL,SRCCOPY);

        }

        if(stage==2)

        {

            if(counter++>63)

            {

                stage=3;

                counter=0;

                return;

            }

        for(int i=0;i<BMP_SIZE;i++)

            p3[i]=(64-counter)*p1[i]/64+counter*p2[i]/64;

            ::StretchDIBits(GetDC()->m_hDC,x_offset,y_offset,640,400,0,0,320,200,p3,

                ((BITMAPINFO*)(&header)),NULL,SRCCOPY);

        }

        if(stage==3)

        {

            if(counter++>63)

            {

                KillTimer(1);

                SendMessage(WM_CLOSE);

                return;

            }

        for(int i=0;i<BMP_SIZE;i++)

            p3[i]=(64-counter)*p2[i]/64;

            ::StretchDIBits(GetDC()->m_hDC,x_offset,y_offset,640,400,0,0,320,200,p3,

                ((BITMAPINFO*)(&header)),NULL,SRCCOPY);

        }

    //////////////////////////////////

    13:最后,將兩個分辨率為320*200的24bitBMP拷入工程所在的目錄中,分別命名為1.bmp和2.bmp. 編譯運行程序,可以看到在黑色的背景中,第一幅圖象(1.bmp)由暗漸漸變亮,當它完全出現后,第二幅圖象(2.bmp)從第一幅圖象中慢慢的浮現出來。當第二幅圖象完全取代第一幅后,它的亮度又逐漸減小,最終消失在黑色的背景中。與模式畫刷法不同,這些過渡非常平滑。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>