首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

Windows 動畫特技實作:淡入淡出效果完整指南

     編輯:VC 教學

前言

動畫能讓介面生動活潑,且不需特殊多媒體硬體支援。本文以經典「淡入淡出」為例,說明如何結合 Windows GDI、調色板與三元光柵操作 (ROP) 在 Visual C++ 中實現位圖淡入淡出轉場。

一、淡入淡出原理

電影業起源技術:製作中間過渡影格。電腦上則採「打洞法」——在已顯示的位圖 A 上逐步開啟微小洞口,透出位圖 B 的像素。洞口越多,A 越模糊,B 越清晰,最終完全切換至 B。

二、Windows 調色板機制

256 色模式下,系統調色板 (硬體調色板) 為共享資源。Windows 引入邏輯調色板:

  • 系統調色板保留前 10/後 10 色為靜態系統色。
  • 邏輯調色板項目優先完全匹配 (RGB 相同) 系統調色板項目。
  • 剩餘項目映射至系統調色板空閒項,或最接近色彩 (不完全匹配)。
  • 活動視窗優先獲得色彩滿足,其餘依 Z-order 分配。

MFC 提供 CPalette、CDC 封裝調色板操作:

  • CPalette::CreatePalette() 建立調色板
  • CDC::SelectPalette() 選入裝置
  • CDC::RealizePalette() 實現調色板映射

三、BitBlt 與三元光柵操作 (ROP)

CDC::BitBlt 在來源與目的裝置位圖間執行邏輯運算,涉及三個對象:目的畫刷、來源位圖、目的位圖。畫刷為 8×8 單色位圖,可用 CreatePatternBrush 建立。

淡入淡出 ROP 碼推導

過程分兩步:

  1. 畫刷在目的位圖打洞:Pattern & Destination (黑=0 保留洞,白=1 保留原像素)。
  2. 來源位圖填入洞口:(~Pattern) & Source (黑處取來源,白處為 0)。
  3. 兩步 OR 合併:(Pattern & Destination) | ((~Pattern) & Source)。

代入 Pattern=0xF0, Destination=0xAA, Source=0xCC 計算得 ROP 碼 0x00AC0744。

四、完整實作範例

專案建立

  1. AppWizard 建立對話框基礎專案。
  2. 刪除預設控制項,準備繪圖區域。

畫刷產生演算法

CBrush* CDissolve::CreateDissolveBrush(int Step)
{
    // 8x8=64 個像素的擴散序列 (Bayer dithering 順序)
    static int data[65] = {
        1, 5, 33, 37, 19, 23, 51, 55, 17, 21, 49, 53, 3, 7, 35, 39,
        10, 14, 42, 46, 28, 32, 60, 64, 26, 30, 58, 62, 12, 16, 44, 48,
        8, 4, 40, 36, 22, 18, 54, 50, 24, 20, 56, 52, 6, 2, 38, 34,
        15, 11, 47, 43, 29, 25, 61, 57, 31, 27, 63, 59, 13, 9, 45, 41
    };

    if (Step < 0 || Step >= m_maxstep) return NULL;

    CBrush* pBrush = new CBrush;
    if (Step == m_maxstep - 1) // 最後一步全黑畫刷
    {
        pBrush->CreateSolidBrush(RGB(0,0,0));
        return pBrush;
    }

    BYTE pixels[16] = {0};
    for (int i = 0; i < 8; i++) pixels[i*2] = 0xFF; // 初始全白 (11111111)

    int pixelsToClear = Step * (64 / m_maxstep);
    for (int i = 1; i <= pixelsToClear; i++)
    {
        int idx = data[i] - 1;
        int row = idx / 8;
        int col = idx % 8;
        pixels[row*2] &= ~(BYTE)pow(2, col); // 將對應位清為 0 (打洞)
    }

    CBitmap bitmap;
    if (!bitmap.CreateBitmap(8, 8, 1, 1, pixels)) return NULL;
    if (!pBrush->CreatePatternBrush(&bitmap)) return NULL;

    return pBrush;
}

繪製邏輯 (OnPaint 中)

void CDissolveDlg::OnPaint()
{
    CPaintDC dc(this);
    CRect rect; GetClientRect(&rect);

    // 雙緩衝防閃爍
    CMemDC memDC(dc, &rect);
    CDC* pDC = &memDC;

    // 繪製來源位圖 B 到記憶體 DC
    pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &srcDC, 0, 0, SRCCOPY);

    // 依步驟產生畫刷並執行淡入淡出 ROP
    for (int step = 0; step < m_maxstep; step++)
    {
        CBrush* pBrush = CreateDissolveBrush(step);
        if (!pBrush) continue;

        CBrush* pOldBrush = pDC->SelectObject(pBrush);
        pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &destDC, 0, 0, 0x00AC0744);
        pDC->SelectObject(pOldBrush);
        delete pBrush;

        Sleep(30); // 控制動畫速度
    }
}

五、關鍵技巧總結

  • 雙緩衝:使用 CMemDC (記憶體 DC) 先畫好再一次 BitBlt 到螢幕,消除閃爍。
  • 調色板實現:256 色模式下,動畫前後需呼叫 RealizePalette 確保色彩正確。
  • 畫刷序列:採用 Bayer 矩陣順序使視覺擴散均勻自然。
  • ROP 碼計算:理解三元光柵邏輯可自行推導各種混合效果。

結語

淡入淡出是基礎且實用的轉場動畫。掌握調色板、畫刷、ROP 運算與雙緩衝技巧,即可擴展至更豐富的視覺效果 (如推拉、百葉窗、溶解等)。本文範例程式碼可直接整合至 MFC 專案中使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved