游戏开发论坛

 找回密码
 立即注册
搜索
查看: 7258|回复: 12

在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题

[复制链接]

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
发表于 2009-4-27 22:40:00 | 显示全部楼层 |阅读模式
在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题如何解决?
问题:按照我的思路是,内存拷贝绘图在API绘图之后,因该会把API绘制的图形遮挡,但事实相反,API绘制的图形永远都在内存拷贝绘制的图形之上,这是为什么,请各位大侠帮帮小弟!
截图如下:

绘图代码如下:

//开始绘图
GDI.BeginDraw();
        GDI.EraseBackground();//擦除背景
        //API绘制打印信息
        for( int i = 0; i < PrinterSystem.GetPrinterCount(); i++ )
        {
                ::memset( szBuffer, 0, NUMLINES( szBuffer ) );
                ::TextOut( GDI.GetRenderDC(), 10, cyChar * i, szBuffer,
wsprintf ( szBuffer, TEXT("%d : %s"), i, PrinterSystem.GetPrinterName(i).c_str() ) );
        }
        //API绘制一矩形框
        Rectangle( GDI.GetRenderDC(), 0, 0, 100, 100 );
        //通过内存拷贝绘制一位图
        GDI.DrawImage( ButtonPosX, ButtonPosY,
                                        ButtonW, ButtonH,
                                        pButtonData );
GDI.EndDraw();
//结束绘图

说明:
其中的GDI是CGDI类的一个对象,CGDI类定义如下:

//绘制系统
class CGDI
{
public:
        CGDI()
        {
                ::memset( this, 0, sizeof( *this ) );
        }
        ~CGDI(){}

        bool Initialize( HWND hWnd, unsigned long w, unsigned long h );
        bool Release();
        bool BeginDraw();
        bool EraseBackground();
        bool DrawImage( long x, long y,
                                unsigned long ulWidth, unsigned long ulHeight,
                                unsigned char* pData );
        bool EndDraw();
        HDC GetRenderDC(){return m_hRenderDC;}
        bool ReSize( unsigned long w, unsigned long h );
private:
        unsigned long m_ulWidth;
        unsigned long m_ulHeight;
        HWND m_hWnd;
        HDC        m_hDC;
        HDC        m_hRenderDC;
        HBITMAP m_hRenderBMP;
        unsigned char* m_pRenderBuffer;
};

实现如下:
//绘制系统
bool CGDI::Initialize( HWND hWnd, unsigned long w, unsigned long h )
{
        if( NULL == hWnd )return false;
        if( 0 == w || 0 == h )return false;
        m_hWnd = hWnd;
        m_ulWidth = w;
        m_ulHeight = h;
        m_hDC = ::GetDC ( m_hWnd );
        if( NULL == m_hDC )return false;
        m_hRenderDC = ::CreateCompatibleDC( m_hDC );
        if( NULL == m_hRenderDC )return false;
        New( &m_pRenderBuffer, m_ulWidth*m_ulHeight*4 );
        if( NULL == m_pRenderBuffer )return false;
        ::memset( m_pRenderBuffer, 0, m_ulWidth*m_ulHeight*4 );
        return true;
}
bool CGDI::Release()
{
        if( NULL != m_hRenderBMP ):eleteObject( m_hRenderBMP );
        if( NULL != m_hRenderDC )::DeleteDC ( m_hRenderDC );
        if( NULL != m_hWnd && NULL != m_hDC )::ReleaseDC( m_hWnd, m_hDC );
        ReleasePointer( m_pRenderBuffer );
        return true;
}
bool CGDI::BeginDraw()
{
        m_hRenderBMP = ::CreateBitmap( m_ulWidth, m_ulHeight, 1, 32, m_pRenderBuffer );
        ::SelectObject( m_hRenderDC, m_hRenderBMP );
        return true;
}
bool CGDI::EraseBackground()
{
        ::memset( m_pRenderBuffer, 0, m_ulWidth*m_ulHeight*4 );
        return true;
}
bool CGDI::DrawImage( long x, long y,
                                unsigned long ulWidth, unsigned long ulHeight,
                                unsigned char* pData )
{
        if( x >= (long)m_ulWidth || y >= (long)m_ulHeight || x <= (long)-ulWidth || y <= (long)-ulHeight )return false;
        if( NULL == pData )return false;
        long SL = 0, ST = 0;
        long DL = 0, DT = 0;
        long W = 0,        H = 0;
        if( x < 0 )
        {
                SL = -x;
                DL = 0;
                W = ulWidth - SL;
                if( W > m_ulWidth )W = m_ulWidth;
        }
        else
        {
                SL = 0;
                DL = x;
                W = ulWidth;
                if( ( W + DL ) > m_ulWidth )W = m_ulWidth - DL;
        }
        if( y < 0 )
        {
                ST = -y;
                DT = 0;
                H = ulHeight - ST;
                if( H > m_ulHeight )H = m_ulHeight;
        }
        else
        {
                ST = 0;
                DT = y;
                H = ulHeight;
                if( ( H + DT ) > m_ulHeight )H = m_ulHeight - DT;
        }
        long S = 0, D = 0, A = 0, cx = 0, cy = 0;
        for( cy = 0; cy < H; cy++ )
        {
                for( cx = 0; cx < W; cx++ )
                {
                        A = ( int )pData[ ( ( cy + ST ) * ulWidth + ( cx + SL ) ) * 4 + 3 ];
                       
                        S = ( int )pData[ ( ( cy + ST ) * ulWidth + ( cx + SL ) ) * 4 ];
                        D = ( int )m_pRenderBuffer[ ( ( cy + DT ) * m_ulWidth + ( cx + DL ) ) * 4 ];
                        D = S * A + D * ( 255 - A );
                        D = D >> 8;
                        m_pRenderBuffer[ ( ( cy + DT ) * m_ulWidth + ( cx + DL ) ) * 4 ] = ( unsigned char )D;

                        S = ( int )pData[ ( ( cy + ST ) * ulWidth + ( cx + SL ) ) * 4 + 1];
                        D = ( int )m_pRenderBuffer[ ( ( cy + DT ) * m_ulWidth + ( cx + DL ) ) * 4 + 1 ];
                        D = S * A + D * ( 255 - A );
                        D = D >> 8;
                        m_pRenderBuffer[ ( ( cy + DT ) * m_ulWidth + ( cx + DL ) ) * 4 + 1 ] = ( unsigned char )D;

                        S = ( int )pData[ ( ( cy + ST ) * ulWidth + ( cx + SL ) ) * 4 + 2];
                        D = ( int )m_pRenderBuffer[ ( ( cy + DT ) * m_ulWidth + ( cx + DL ) ) * 4 + 2 ];
                        D = S * A + D * ( 255 - A );
                        D = D >> 8;
                        m_pRenderBuffer[ ( ( cy + DT ) * m_ulWidth + ( cx + DL ) ) * 4 + 2 ] = ( unsigned char )D;
                }
        }
        return true;
}
bool CGDI::EndDraw()
{
        ::BitBlt ( m_hDC, 0, 0, m_ulWidth, m_ulHeight, m_hRenderDC, 0, 0, SRCCOPY );
        ::DeleteObject( m_hRenderBMP );
        return true;
}
bool CGDI::ReSize( unsigned long w, unsigned long h )
{
        if( 0 == w || 0 == h )return false;
        if( m_ulWidth != w || m_ulHeight != h )
        {
                ReleasePointer( m_pRenderBuffer );
                New( &m_pRenderBuffer, w*h*4 );
                if( NULL == m_pRenderBuffer )return false;
                ::memset( m_pRenderBuffer, 0, w*h*4 );
        }
        m_ulWidth = w;
        m_ulHeight = h;
        return true;
}

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
 楼主| 发表于 2009-4-27 22:46:00 | 显示全部楼层

Re: 在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问

bluebaby9811: 在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题如何解决?

在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题如何解决?
[color=#ff9900...


截图

0

主题

2

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2009-4-28 13:53:00 | 显示全部楼层

Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问

具体为啥我不知道,不过你用API绘图和拷贝都在一个内存DC上,最后再把这个内存DC拷贝绘图就可以了。(其实就是双缓冲即可解决)

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
 楼主| 发表于 2009-4-28 22:51:00 | 显示全部楼层

Re: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡

飞燕十刃: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题如何解决?

具体为啥我不知道,不过你用API绘图和拷贝都在一个内存DC上,最后再把这个内存DC拷贝绘图就可以了。(其实就是双缓冲即可解决)


问题补充:
我的思路是,用API函数在内存DC上绘图,像素因该是输出在创建被选进内存DC中的位图句柄的缓冲区中。之后我用
bool CGDI:rawImage( long x, long y,
                                unsigned long ulWidth, unsigned long ulHeight,
                                unsigned char* pData )
绘制一位图,此函数直接拷贝像素到此缓冲区中。
然后在
bool CGDI::EndDraw()
调用里BitBlt到前台DC中。
按道理,DrawImage绘制的像素会覆盖掉API绘制的像素,但事实相返,无论我颠倒DrawImage和 API的绘制顺序,结果始终是API绘制的像素覆盖掉DrawImage绘制的像素。
百思不得其解,难道用API函数在内存DC上绘图,像素不是输出在创建被选进内存DC中的位图句柄的缓冲区中。那它又输出在哪里?
请各位大侠帮忙看看!

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
 楼主| 发表于 2009-4-28 23:05:00 | 显示全部楼层

Re: Re: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮

bluebaby9811: Re: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题如何解决?



问题补充:
我的思路是,用API函数在内存DC上绘图,像素因该是输出在创建被选进内存DC中的位图句柄的缓...


难到API函数是推迟到BitBlt时才绘制的吗?

32

主题

1583

帖子

1589

积分

金牌会员

Rank: 6Rank: 6

积分
1589
发表于 2009-5-25 22:55:00 | 显示全部楼层

Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问

[em7]
好糟糕的代码,你是打算实现AlphaBlend么?为何不用GdiAlphaBlend实现,而非要自己写一个诡异的drawImage,而且每次绘图都创建一个bitmap之后又删掉,相当奢侈啊。

我认为你的思路就有问题,你想要直接操纵位图内存,应该用CreateDIBSection,而不是CreateBitmap。如果我没有理解错的话,MSDN上说CreateBitmap最后一个参数传入的指针是用于“指明填充位图的数据所在地”,而不是“直接把指向的地方当作位图数据的存放地”。

根据我的测试,当CreateBitmap之后,你再对那个指针指向的区域做任何修改都不会影响到位图的数据了。也就是说其实CreateBitmap是把你的m_pRenderBuffer里面的数据拷贝到它的位图数据区去了,你之后再怎么修改m_pRenderBuffer都和Create出来的Bitmap无关了。因此你那个DrawImage根本对当前的m_hRenderBMP或m_hRenderDC无效,根本绘不上去。只会因为m_pRenderBuffer中残留的数据而影响下一次绘制。

也就是说,我强烈怀疑你所说的DrawImage被Rectangle覆盖在下面了是因为:那是你上次调用DrawImage残留的效果,而不是你当前绘制的结果。因为你给的使用代码貌似不全,我只能这样猜测了。

[em15]  [em13]

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
 楼主| 发表于 2009-5-26 20:31:00 | 显示全部楼层

Re: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡

sandy_zc_1: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题如何解决?

[em7]
好糟糕的代码,你是打算实现AlphaBlend么?为何不用GdiAlphaBlend实现,而非要自己写一个诡异的draw...


sandy_zc_1,你说的很有道理,谢谢你的解答。不过我已找到解决的办法了,就是GDI+,而且功能更强大。

32

主题

1583

帖子

1589

积分

金牌会员

Rank: 6Rank: 6

积分
1589
发表于 2009-5-27 02:07:00 | 显示全部楼层

Re: Re: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮

bluebaby9811: Re: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题如何解决?



sandy_zc_1,你说的很有道理,谢谢你的解答。不过我已找到解决的办法了,就是GDI+,而且功能更强大。


不要对GDI+抱有太大幻想,当初我第一次看它的文档时候也被它丰富的功能所折服,后来才发现,GDI+效率不是一般的低,几乎到了不能在游戏中随意使用的地步。简单的2D游戏GDI还是主流,GDI+就算用也是稍做辅助而已。

3

主题

101

帖子

101

积分

注册会员

Rank: 2

积分
101
发表于 2009-6-3 13:02:00 | 显示全部楼层

Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问

可能你的DrawImage区域,小于API所绘的区域,所以API所绘的部分区域可见.

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
 楼主| 发表于 2009-6-20 16:30:00 | 显示全部楼层

Re: Re: Re: Re:在内存DC中,同时用API绘图和内存拷贝绘图时

sandy_zc_1: Re: Re: Re:在内存DC中,同时用API绘图和内存拷贝绘图时的遮挡问题如何解决?



不要对GDI+抱有太大幻想,当初我第一次看它的文档时候也被它丰富的功能所折服,后来才发现,GDI+效率不...


是吗,GDI+的效率不如GDI可能是因为它的一些功能是通过GDI来实现的,但用它来做商业软件足足有余了,而且它提供的功能比GDI多得多,尤其ALPHA混合我最看中,作为一个图形库这是很重要的功能,但GDI为什么就不支持呢。我用GDI+配合内存DC双缓冲使用,也没感觉到它效率低,这是我的一点成果,大家可以参考参考。呵呵!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-20 16:44

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表