SetLayeredWindowAttributes使窗口透明只是一部分时间 [英] SetLayeredWindowAttributes to make a window transparent is only working part of the time

查看:65
本文介绍了SetLayeredWindowAttributes使窗口透明只是一部分时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使一个窗口透明,以便只显示部分内容,我尝试使用 SetLayeredWindowAttributes 来实现此目的,这使窗口可以根据需要透明,但是仅当Windows图片的一部分位于桌面的可见区域之外时,它才这样工作.由于某种原因,无论何时窗口完全在屏幕上,它都会重新绘制其黑色背景(我用来表示透明的颜色是本来就不会出现的.)

I'm trying to make a window transparent so that only part of its contents are visible, I've tried using SetLayeredWindowAttributes to make this happen, this made the window transparent as I wanted, however it only works that way when part of the windows picture is outside of the visible area of my desktop. For some reason whenever the window is fully on screen it re-draws its black background (the color I use for transparency that's meant not to be seen.) Here is a video example of the problem. I'm not sure what exactly is causing this to just to be safe I'm posting the full code.

#define _WIN32_WINNT 0x501
#include "C:\Program Files\Microsoft DirectX SDK (August 2008)\Include\D3dx9core.h"
#include "C:\Documents and Settings\Death\My Documents\Downloads\DXSprite\DXSprite\resource.h"
#include <windows.h>
#include <string>
#include <stdio.h>
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
HWND                        g_hWnd                  = NULL;
LPDIRECT3D9                 g_pD3D                  = NULL;
LPDIRECT3DDEVICE9           g_pD3DDevice            = NULL;
ID3DXSprite *               g_pD3DXSprite           = NULL;
LPDIRECT3DTEXTURE9          g_pTexture              = NULL;
const int                   SCREEN_WIDTH            = 800;
const int                   SCREEN_HEIGHT           = 600;
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT InitializeD3D       ( );
void RenderFrame            ( );

//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance,
                HINSTANCE hPrevInstance,
                LPSTR     lpCmdLine,
                int       nCmdShow )
{
WNDCLASSEX  winClass;
MSG         uMsg;
HRESULT     hr;

memset(&uMsg,0,sizeof(uMsg));

winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize        = sizeof(WNDCLASSEX);
winClass.style         = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc   = WindowProc;
winClass.hInstance     = hInstance;
winClass.hIcon         = LoadIcon(hInstance, (LPCTSTR)IDC_DXSPRITE);
    winClass.hIconSm       = LoadIcon(hInstance, (LPCTSTR)IDC_DXSPRITE);
winClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName  = NULL;
winClass.cbClsExtra    = 0;
winClass.cbWndExtra    = 0;

if( !RegisterClassEx(&winClass) )
    return E_FAIL;

g_hWnd = CreateWindowEx( WS_EX_LAYERED, "MY_WINDOWS_CLASS",
                         "Direct3D 9 - ID3DXSprite Example",
                         WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
                         0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL );

if( g_hWnd == NULL )
    return E_FAIL;

SetLayeredWindowAttributes(g_hWnd, RGB(0x00,0x00,0x00), 0, LWA_COLORKEY});
ShowWindow( g_hWnd, nCmdShow );
//----------------------------------------------------------------
// Create the DirectX device
//----------------------------------------------------------------
if (FAILED( InitializeD3D()))
    return 0;


//----------------------------------------------------------------
// CREATE THE ID3DXSprite
//----------------------------------------------------------------

// Create the ID3DXSprite interface object
hr = D3DXCreateSprite(g_pD3DDevice, &g_pD3DXSprite );
if( FAILED(hr) )
    return hr;


//----------------------------------------------------------------
// LOAD THE TEXTURE FOR THE SPRITE
//----------------------------------------------------------------

// --------------------------------------------------------
// Load the texture.  I decided to use the extended
// version of the texture loading function just to show what
// it would look like.
// The texture was created with Photoshop with a transparent
// background to start with.  Then line cross hairs were added.
//
// Note - If you don't use a texture image that has a power of
// 2 size for the width or height then the image may not load
// properly.  This image is 256x256.
//
D3DXCreateTextureFromFileEx(
    g_pD3DDevice,
    "C:\\Documents and Settings\\Death\\My Documents\\45handold2.tga",              // Our texture image!
    D3DX_DEFAULT,               // width
    D3DX_DEFAULT,               // height
    D3DX_DEFAULT,               // MIP levels
    0,                          // usage
    D3DFMT_DXT1,                // texture format
    D3DPOOL_MANAGED,            // mem pool
    D3DX_DEFAULT,               // filter
    D3DX_DEFAULT,               // MIP filter
    0,                          // transparent color key
    NULL,                       // image info struct
    NULL,                       // palette
    &g_pTexture);               // the returned texture, if success

if ( FAILED(hr) )
    return hr;





// ---------
// Main Loop
// ---------
while( uMsg.message != WM_QUIT )
{
    if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
    {
        TranslateMessage( &uMsg );
        DispatchMessage( &uMsg );
    }
}

// -------------------------
// Release directx resources
// -------------------------
if (g_pD3DXSprite)
{
    g_pD3DXSprite->Release();
    g_pD3DXSprite = NULL;
}

if (g_pTexture)
{
    g_pTexture->Release();
    g_pTexture = NULL;
}

if (g_pD3DDevice)
{
    g_pD3DDevice->Release();
    g_pD3DDevice = NULL;
}




UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );
return (int)uMsg.wParam;
}

//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND   hWnd,
                         UINT   msg,
                         WPARAM wParam,
                         LPARAM lParam )
{

switch( msg )
{
    case WM_KEYDOWN:
    {
        switch( wParam )
        {
            case VK_ESCAPE:
                PostQuitMessage(0);
                break;

        }
    }
    break;

    case WM_CLOSE:
    {
        PostQuitMessage(0);
    }

    case WM_DESTROY:
    {
        PostQuitMessage(0);
    }
    break;

    default:
    {
        RenderFrame();
        return DefWindowProc( hWnd, msg, wParam, lParam );
    }
    break;
}

return 0;
}

//-----------------------------------------------------------------------------
// Name: InitializeD3D()
// Desc: Create DirectX interface objects
//       Initialize the view matrix.
//       Setup render states that will not need changing throughout
//       the life of the application.
//-----------------------------------------------------------------------------
HRESULT InitializeD3D( )
{
HRESULT hr;

// Create a direct 3D interface object
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );

if( g_pD3D == NULL )
{
    // TO DO: Respond to failure of Direct3DCreate9
    return E_FAIL;
}

D3DDISPLAYMODE d3ddm;

if( FAILED( hr = g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
{
    // TO DO: Respond to failure of GetAdapterDisplayMode
    return hr;
}


//
if( FAILED( hr = g_pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
                                            d3ddm.Format, D3DUSAGE_DEPTHSTENCIL,
                                            D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
{
    if( hr == D3DERR_NOTAVAILABLE )
        // POTENTIAL PROBLEM: We need at least a 16-bit z-buffer!
        return hr;
}

//
// Do we support hardware vertex processing? If so, use it.
// If not, downgrade to software.
//

D3DCAPS9 d3dCaps;

if( FAILED( hr = g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT,
                                   D3DDEVTYPE_HAL, &d3dCaps ) ) )
{
    // TO DO: Respond to failure of GetDeviceCaps
    return hr;
}

DWORD dwBehaviorFlags = 0;

if( d3dCaps.VertexProcessingCaps != 0 )
    dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
    dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;

//
// Everything checks out - create a simple, windowed device.
//

D3DPRESENT_PARAMETERS d3dpp;
memset(&d3dpp, 0, sizeof(d3dpp));

d3dpp.BackBufferFormat       = d3ddm.Format;
d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed               = TRUE;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_IMMEDIATE;

// Attempt to create a HAL device, end app on failure just to keep things
// simple.  In other words we are not trying to create a REF device if the
// HAL fails.
if( FAILED( hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd,
                                  dwBehaviorFlags, &d3dpp, &g_pD3DDevice ) ) )
{
//    char blah[100];
  //  snprintf (blah, 1000, "%d", hr);
    //MessageBox (NULL,blah,NULL,NULL);
}


// If we get here everything worked!
return S_OK;
}


//-----------------------------------------------------------------------------
// Name: RenderFrame()
// Desc: Draw the image to the framebuffer.
//-----------------------------------------------------------------------------
void RenderFrame( )
{
if (!g_pD3DDevice && !g_pD3DXSprite && !g_pTexture)
    return;


// Clear the frame & depth buffer ready for drawing (Black color)
g_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,  0x00000000, 1.0f, 0     );

g_pD3DDevice->BeginScene();
{
    //-------------------------
    // Render the sprite
    //

    D3DXVECTOR3 vecPos = D3DXVECTOR3(0,0,0);

    if (g_pD3DXSprite && g_pTexture)
    {
        g_pD3DXSprite->Begin( D3DXSPRITE_ALPHABLEND );
        g_pD3DXSprite->Draw(g_pTexture, NULL, NULL, &vecPos, 0xffffffff);
        g_pD3DXSprite->End();
    }


}
g_pD3DDevice->EndScene();


// Frame buffer to Front buffer
g_pD3DDevice->Present( NULL, NULL, NULL, NULL );

}

推荐答案

您遇到的问题基本上是Windows中曾经有两个完全独立的渲染堆栈:GDI和Direct3D.他们之间并没有真正交谈,因此标准窗口和GDI API对Direct3D一无所知.当Vista出现时,他们统一了两个驱动程序堆栈,但是GDI代码(通常来说)仍然对Direct3D一无所知,即使它内部在幕后使用了Direct3D(用于桌面合成).

The problem you're running into is basically that there used to be two entirely separate rendering stacks in Windows: GDI and Direct3D. They didn't really talk to one another at all, so standard windowing and GDI APIs don't really know anything about Direct3D. When Vista came along they unified the two driver stacks, but the GDI code (generally speaking) still knows nothing about Direct3D, even if it internally uses some Direct3D behind the scenes (for desktop composition).

简而言之, SetLayeredWindowAttributes UpdateLayeredWindow 不能也不知道您的Direct3D交换链.如果您在Windows XP或2000上尝试过此方法,我希望您会得到一些非常时髦的视觉效果.我应该补充说,确实有一些很好的理由.例如,在GDI世界中,使用 UpdateLayeredWindow 设置具有每个像素alpha的位图实际上会导致alpha值为零的地方被视为不属于窗口的一部分.换句话说,点击会传递到下面的窗口.为了使用Direct3D来实现这一点,系统必须将Direct3D纹理从GPU读回CPU内存(这是相当昂贵的),然后执行命中测试.

In short, SetLayeredWindowAttributes as well as UpdateLayeredWindow cannot and do not know about your Direct3D swapchain. If you had tried this back on Windows XP or 2000 I expect you would have gotten some really funky visual results. There are some really good reasons for this, I should add. For example, in the GDI world, using UpdateLayeredWindow to set a bitmap with per-pixel alpha actually results in places with an alpha value of zero being treated as not part of the window. In other words, clicks pass through to the window underneath. In order to implement this with Direct3D, the system would have to read back the Direct3D texture from GPU to CPU memory, which is quite expensive, and then perform the hit test.

当然,一种解决方案是使用GDI渲染窗口,包括颜色键.我假设您出于性能原因将其排除在外.

One solution, of course, is to use GDI to render the window, including the color key. I'm assuming you ruled that out for performance reasons.

我不能完全确定您期望的视觉效果,但是如果您想在具有完全硬件加速且没有窗口边框的窗口中渲染任意alpha混合内容,则可以创建无边界窗口(例如,仅WS_POPUP为其窗口样式),然后调用DwmExtendFrameIntoClientArea 为所有边距传递-1.然后,使用D3DFMT_A8R8G8B8像素格式或与DXGI等效的Direct3D 10/11(DWM用于渲染窗口的本机格式)创建交换链并将其渲染.现在,您有一个窗口,其中仅包含叠加在桌面上的Alpha混合内容.关于这个主题,有旧文章有关CodeProject的旧文章.

I'm not entirely sure of the visual results you are expecting, but if you want to render arbitrary alpha-blended content in a window with full hardware acceleration and no window border, you can create a borderless window (e.g. just WS_POPUP for its window style) and call DwmExtendFrameIntoClientArea passing -1 for all the margins. Then, create your swap-chain with the D3DFMT_A8R8G8B8 pixel format or the DXGI equivalent for Direct3D 10/11 (which is the native format DWM uses to render windows) and render into it. You now have a window that contains only your alpha-blended content superimposed on the desktop. There is an older article on CodeProject about this very topic.

这篇关于SetLayeredWindowAttributes使窗口透明只是一部分时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆