minigui重要的DC memory绘图过程

一、引言

上一章 minigui相关硬件加速添加方法 介绍了从绘图到显示的整体流程,以及最终调用到的硬件加速方法。如果我们不用DC MEM的话那将是每一次FillBoxWithBitmap ,以及DrawText,settext都会是直接调用到硬件的updateRect直接画出来,可以看到icon以及字符是一个一个刷出来的,这个也可以在updaterect处加打印验证。为了避免这样的问题,我们使用DC mem可以在整个window画完后再调用updateRect将整个window更新到framebuffer。
这一章我们重点介绍私有以及DC mem绘制的过程,主要分析入口为上一章的dialog callback的print msg中绘图部分。如下:

static int InitDialogBoxProc (HWND hDlg, int message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
    case MSG_INITDIALOG:
        return 1;       
    case MSG_COMMAND:
        switch (wParam) {
        case IDOK:
        case IDCANCEL:
            EndDialog (hDlg, wParam);
            break;
        }
        break;
    case MSG_PAINT:
    			 //画多个图标到secondary DC 
    		hdc = BeginPaint (hWnd);
            FillBoxWithBitmap (hdc, 0, 0, 100, 100, &bmp);
            FillBoxWithBitmap (hdc, 100, 0, 200, 200, &bmp);
            FillBoxWithBitmapPart (hdc, 0, 200, 150, 150, 200, 200, &bmp, 10, 10);
            EndPaint (hWnd, hdc);
    		break;
  }

留意咋们创建的dialog属性是WS_EX_AUTOSECONDARYDC,自动创建窗口子DC。

static DLGTEMPLATE DlgInitProgress =
{
    WS_BORDER | WS_CAPTION, 
    WS_EX_AUTOSECONDARYDC,
    120, 150, 400, 140, 
    the_system_is_initializing,
    0, 0,
    3, NULL,
    0
};

二、流程分析

我们从创建dialog的接口DialogBoxIndirectParam开始分析

DialogBoxIndirectParam
	DialogBoxIndirectParamEx
		CreateMainWindowIndirectParamEx
			CreateMainWindowEx
				SendMessage (HWND_DESKTOP, MSG_ADDNEWMAINWIN, (WPARAM) pWin, 0)
				WindowMessageHandler //desktop-comm.c 接收MSG_ADDNEWMAINWIN消息
					case MSG_ADDNEWMAINWIN:
					return dskAddNewMainWindow(pWin);
						dskAddNewMainWindow
					    if (pWin->dwExStyle & WS_EX_AUTOSECONDARYDC) \\最后在这里创建窗口子dc
        				pWin->secondaryDC = CreateSecondaryDC ((HWND)pWin);
        				CreateSecondaryDC
        					CreateCompatibleDCEx //创建mem DC ,这个接口也是自己创建与fb相同属性的memory dc的接口
        					

接着CreateCompatibleDCEx分析

CreateCompatibleDCEx
	GAL_CreateRGBSurface
	if ( ((flags&GAL_HWSURFACE) == GAL_SWSURFACE) || 
                (video->AllocHWSurface(this, surface) < 0) ) //AllocHWSurface就是硬件加速的分配接口抽象
                GAL_FreeSurface(surface);
                	video->FreeHWSurface(this, surface);//FreeHWSurface是释放硬件分配空间的接口

绘制过程分析:BeginPaint -> FillBoxWithBitmap -> EndPaint ;BeginPaint 的作用我们可以暂时理解为获取hdc句柄的作用。重点分析后面两个函数接口。参考上一篇文章 详解minigui图片加载及显示

分析icon贴图流程为何在mem dc的情况下不会调用updaterect更新到framebuffer。

FillBoxWithBitmap (HDC hdc, int x, int y, int w, int h,  const BITMAP* bmp)
	_begin_fill_bitmap (hdc, x, y, w, h, bmp, &fill_info); //计算填充区域信息
	_fill_bitmap (pdc, bmp, &fill_info);
		_dc_fillbox_bmp_clip (pdc, &fill_info->dst_rect, (BITMAP*)bmp); //不缩放的情况下调用该函数
			GAL_PutBox (pdc->surface, rect, bmp); //开始填充
				GAL_IntersectRect //计算重叠的填充区域 仅计算重绘的区域
				dstrow = (Uint8 *)dst->pixels + my_dstrect.y * dst->pitch + my_dstrect.x * dst->format->BytesPerPixel; //目的framebuffer
    			srcrow = (Uint8 *)box->bmBits + off_y * box->bmPitch + off_x * box->bmBytesPerPixel; //源bitmap
				_PutBoxAlpha (dst, dstrow, srcrow, w, h, box); //根据h高度一行行进行拷贝采用DUFFS_LOOP8拷贝
	_end_fill_bitmap (pdc, bmp, &fill_info); //拷贝完成后更新到真实framebuffer进行显示
		__mg_leave_drawing (pdc);
			 {if (!dc_IsMemDC (pdc)) 
				kernel_ShowCursorForGDI (TRUE, pdc);} //这里这里的dc_IsMemDC (pdc)判断,如果是memory dc就不调用kernel_ShowCursorForGDI 进行updaterect刷新
					GAL_UpdateRect (cur_pdc->surface, prc->left, prc->top, RECTWP(prc), RECTHP(prc)); //调用硬件tde 进行局部更新。

dc_IsMemDC 是关键原型为

static inline BOOL dc_IsMemDC (PDC pdc)
{
    return (pdc->DCType == TYPE_MEMDC);
}

接着咱们分析EndPaint 该函数将会调用updateRect将mem dc刷新到framebuffer

EndPaint
	if (pWin->pMainWin->secondaryDC) { //如果是secondary dc
        if (!IsRectEmpty(&pWin->pMainWin->update_rc)) {
            HDC real_dc = HDC_INVALID;
            real_dc = GetClientDC ((HWND)pWin->pMainWin);
            update_secondary_dc (pWin, hdc, real_dc, 
                    &pWin->pMainWin->update_rc, HT_CLIENT);
               BitBlt (secondary_dc, rc->left, rc->top, //最终调用到bitblt后面的调用就去查看上篇文章
                RECTWP(rc), RECTHP(rc), 
                real_dc, clip_rc.left, clip_rc.top, 0);

三、 memory DC 主要接口

HDC GUIAPI CreateCompatibleDC (HDC hdc);
HDC GUIAPI CreateMemDC (int width, int height, int depth, DWORD flags,
                Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
BOOL GUIAPI ConvertMemDC (HDC mem_dc, HDC ref_dc, DWORD flags);
BOOL GUIAPI SetMemDCAlpha (HDC mem_dc, DWORD flags, Uint8 alpha);
BOOL GUIAPI SetMemDCColorKey (HDC mem_dc, DWORD flags, Uint32 color_key);
void GUIAPI DeleteMemDC (HDC mem_dc); 

定制自己的memory DC然后通过bitblt更新到主窗口的DC可以使用如下代码

 /* 具有 Alpha 通道 的内存 DC:24位,RGB 各占 8 位,无 Alpha 分量 */
    mem_dc = CreateMemDC (400, 100, 24, MEMDC_FLAG_HWSURFACE | MEMDC_FLAG_SRCALPHA | MEMDC_FLAG_SRCCOLORKEY,0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000); 

    /* 输出填充矩形和文本到内存 DC 上 */
    SetBrushColor (mem_dc, RGB2Pixel (mem_dc, 0xFF, 0xFF, 0x00));
    FillBox (mem_dc, 0, 0, 400, 100);
    SetBkMode (mem_dc, BM_TRANSPARENT);
    SetTextColor (mem_dc, RGB2Pixel (mem_dc, 0x00, 0x00, 0xFF));
    TabbedTextOut (mem_dc, 0, 0, "Memory DC with alpha.\n"
                                 "The source DC have alpha per-surface."); 

    /* Blit 到窗口 DC 上 */
    start_tick = GetTickCount ();
    count = 100;
    while (count--) {
        /* 设置内存 DC 的 Alpha 通道 */
        SetMemDCAlpha (mem_dc, MEMDC_FLAG_SRCALPHA | MEMDC_FLAG_RLEACCEL, rand () % 256);
        BitBlt (mem_dc, 0, 0, 400, 100, hdc, rand () % 800, rand () % 800);
    }
    end_tick = GetTickCount ();
    TellSpeed (hwnd, start_tick, end_tick, "Alpha Blit", 100); 

    /* 填充矩形区域, 并输出文字 */
    FillBox (mem_dc, 0, 0, 400, 100);
    SetBrushColor (mem_dc, RGB2Pixel (mem_dc, 0xFF, 0x00, 0xFF));
    TabbedTextOut (mem_dc, 0, 0, "Memory DC with alpha and colorkey.\n"
                                 "The source DC have alpha per-surface.\n"
                                 "And the source DC have a colorkey, \n"
                                 "and RLE accelerated."); 

    /* 设置内存 DC 的透明象素值 */
    SetMemDCColorKey (mem_dc, MEMDC_FLAG_SRCCOLORKEY | MEMDC_FLAG_RLEACCEL,
                    RGB2Pixel (mem_dc, 0xFF, 0xFF, 0x00));
    /* Blit 到窗口 DC 上 */
    start_tick = GetTickCount ();
    count = 100;
    while (count--) {
        BitBlt (mem_dc, 0, 0, 400, 100, hdc, rand () % 800, rand () % 800);
        CHECK_MSG;
    }
    end_tick = GetTickCount ();
    TellSpeed (hwnd, start_tick, end_tick, "Alpha and colorkey Blit", 100); 

    /* 删除内存 DC 对象 */
    DeleteMemDC (mem_dc); 
此处摘自https://blog.csdn.net/jia0511/article/details/8462466

下节补充下模态和非模态

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值