windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/diconfig/fswindow.cpp
2020-09-26 16:20:57 +08:00

404 lines
13 KiB
C++

//-----------------------------------------------------------------------------
// File: FSWindow
//
// Desc: This code will allow you to update a window in DirectDraw full-screen
// exclusive mode on a device that doesn't support GDI. They will also
// handle devices that do support GDI.
//
//
// Copyright (c) 1998-1999 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------
#include "dconfigp.h"
//-----------------------------------------------------------------------------
// Local definitions
//-----------------------------------------------------------------------------
static IDirectDraw7 *ddObject = NULL;
static IDirectDrawSurface7 *ddFrontBuffer = NULL;
static IDirectDrawSurface7 *ddBackBuffer = NULL;
static IDirectDrawClipper *ddClipper = NULL;
static SIZE structSurfaceSize = {0, 0};
static BOOL bNonGDI = FALSE;
static HWND hwndFSWindow = NULL;
static HBITMAP hwndFSWindowBMP = NULL;
static HWND hwndAppWindow = NULL;
//-----------------------------------------------------------------------------
// Name: CreateDibBMP()
// Desc: Created an empty bitmap, used exclusively in CreateBMPFromWindow().
// Note that this is an internal (not exported) function.
//-----------------------------------------------------------------------------
static HBITMAP
CreateDibBMP(HDC hdc, int w, int h, unsigned short bpp)
{
LPVOID lpBits;
struct
{
BITMAPINFOHEADER bi;
DWORD ct[256];
} dib;
dib.bi.biSize = sizeof(BITMAPINFOHEADER);
dib.bi.biWidth = w;
dib.bi.biHeight = h;
dib.bi.biBitCount = bpp;
dib.bi.biPlanes = 1;
dib.bi.biCompression = 0;
dib.bi.biSizeImage = 0;
dib.bi.biClrUsed = 0;
if (bpp == 15)
{
dib.bi.biBitCount = 16;
}
else
if (bpp == 16)
{
dib.bi.biCompression = BI_BITFIELDS;
dib.ct[0] = 0xF800;
dib.ct[1] = 0x07E0;
dib.ct[2] = 0x001F;
}
return CreateDIBSection(hdc, (LPBITMAPINFO) & dib, DIB_RGB_COLORS, &lpBits,
NULL, 0);
}
//-----------------------------------------------------------------------------
// Name: CreateBMPFromWindow()
// Desc: Takes the hwnd of the content window, and returns a bitmap handle.
// Note that this is an internal (not exported) function.
//-----------------------------------------------------------------------------
static HBITMAP
CreateBMPFromWindow(HWND hwnd)
{
RECT rc;
int x;
int y;
int cx;
int cy;
HDC hdcScreen;
HDC hdcMemory;
HBITMAP hbmBitmap;
// Create a bitmap of the window passed in
GetWindowRect(hwnd, &rc);
x = rc.left;
y = rc.top;
cx = rc.right - rc.left;
cy = rc.bottom - rc.top;
hdcScreen = GetDC(NULL);
hdcMemory = CreateCompatibleDC(NULL);
hbmBitmap = CreateDibBMP(hdcScreen, cx, cy, 16);
// BLT the image from screen to bitmap
SelectObject(hdcMemory, hbmBitmap);
BitBlt(hdcMemory, 0, 0, cx, cy, hdcScreen, x, y, SRCCOPY);
DeleteDC(hdcMemory);
ReleaseDC(NULL, hdcScreen);
return hbmBitmap;
}
//-----------------------------------------------------------------------------
// Name: FSWindow_Init()
// Desc: Does preliminary setup of global values for FSWindow. It should get
// called each time DirectDraw surfaces are altered (i.e. changes to the
// device that the client application is running under).
//-----------------------------------------------------------------------------
void
FSWindow_Init(HWND hwndApp, IDirectDraw7 *dd, IDirectDrawSurface7 *FrontBuffer,
IDirectDrawSurface7 *BackBuffer)
{
DDSURFACEDESC2 ddsd;
DDCAPS ddcaps;
// Save handle to application window
hwndAppWindow = hwndApp;
ZeroMemory(&ddcaps, sizeof(ddcaps));
ddcaps.dwSize = sizeof(ddcaps);
dd->GetCaps(&ddcaps, NULL);
if (ddcaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED)
bNonGDI = FALSE;
else
bNonGDI = TRUE;
// Save DirectDraw object passed in
ddObject = dd;
// Save buffers passed in
ddFrontBuffer = FrontBuffer;
ddBackBuffer = BackBuffer;
// Get DirectDraw surface dimensions
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
ddBackBuffer->GetSurfaceDesc(&ddsd);
structSurfaceSize.cx = ddsd.dwWidth;
structSurfaceSize.cy = ddsd.dwHeight;
}
//-----------------------------------------------------------------------------
// Name: FSWindow_Begin()
// Desc: Prepairs the DirectDraw surface depending on 3D hardware. It should
// get called whenever a window (represented by the hwnd parameter) needs
// to be displayed under DirectDraw. FSWindow_Begin() should also get
// called if the window changes its content (if its static content
// becomes dynamic, and vice-versa).
//-----------------------------------------------------------------------------
HWND
FSWindow_Begin(HWND hwnd, BOOL bStaticContent)
{
RECT rc;
// If no handle passed in, assume existing content window
if (hwnd == NULL)
hwnd = hwndFSWindow;
if (hwnd == NULL)
return NULL;
if (bNonGDI)
{
// Constrain cursor to DirectDraw surface
rc.left =0;
rc.top = 0;
rc.right = structSurfaceSize.cx;
rc.bottom = structSurfaceSize.cy;
ClipCursor(&rc);
// Clear out lingering content
if (hwndFSWindowBMP)
DeleteObject(hwndFSWindowBMP);
hwndFSWindowBMP = NULL;
// Need to create an image of content window just once
if (bStaticContent)
{
if (!FSWindow_IsActive())
UpdateWindow(hwnd);
// Assign content window image to global
hwndFSWindowBMP = CreateBMPFromWindow(hwnd);
}
}
else
{
//Create a clipper (used in IDirectDrawSurface::Blt call)
if (ddObject->CreateClipper(0, &ddClipper, NULL) == DD_OK)
ddClipper->SetHWnd(0, hwndAppWindow);
// Normal GDI device, so just flip to GDI so content window can be seen
ddObject->FlipToGDISurface();
}
hwndFSWindow = hwnd;
return hwndFSWindow;
}
//-----------------------------------------------------------------------------
// Name: FSWindow_End()
// Desc: Deletes objects associated with the content window. Note that these
// are objects created within this module, not objects created by the
// calling client (e.g. content window). Call this function whenever the
// content window is destroyed (e.g. WM_CLOSE).
//-----------------------------------------------------------------------------
void
FSWindow_End()
{
if (hwndFSWindow)
hwndFSWindow = NULL;
if (hwndFSWindowBMP)
DeleteObject(hwndFSWindowBMP);
hwndFSWindowBMP = NULL;
if (bNonGDI)
ClipCursor(NULL);
// Get rid of clipper object
if (ddClipper)
{
ddClipper->Release();
ddClipper = NULL;
}
}
//-----------------------------------------------------------------------------
// Name: FSWindow_Update()
// Desc: Is responsible for the actual rendering of the content window
// (held in global hwndFSWindow). This function must be called each
// time a DirectDraw frame gets rendered and FSWindow_IsActive() returns
// TRUE, so it should be placed in the main application's DirectDraw
// rendering routine. An example of this might look like the following:
//
// void RenderFrame()
// {
// if (FSWindow_IsActive())
// FSWindow_Update();
// else
// FrontBuffer->Blt(...);
// }
//-----------------------------------------------------------------------------
void
FSWindow_Update()
{
POINT pt;
RECT rc;
int x;
int y;
int cx;
int cy;
HDC hdcScreen;
HDC hdcBackBuffer;
HRGN hrgn;
HDC hdcMemory;
static HCURSOR MouseCursor;
static ICONINFO IconInfo;
HCURSOR MouseCursorCur;
if (bNonGDI)
{
GetWindowRect(hwndFSWindow, &rc);
x = rc.left;
y = rc.top;
cx = rc.right - rc.left;
cy = rc.bottom - rc.top;
// Get a DC to the screen (where our window is) and
// Get a DC to the backbuffer on the non-GDI device (where we need to copy it)
hdcScreen = GetDC(NULL);
ddBackBuffer->GetDC(&hdcBackBuffer);
// If window has a complex region associated with it, be sure to include it in the draw
hrgn = CreateRectRgn(0, 0, 0, 0);
if (GetWindowRgn(hwndFSWindow, hrgn) == COMPLEXREGION)
{
OffsetRgn(hrgn, rc.left, rc.top);
SelectClipRgn(hdcBackBuffer, hrgn);
}
// If content window is static (no animations, roll-overs, etc.) then
// create a dc for the bitmap and blt to the back buffer
if (FSWindow_IsStatic())
{
hdcMemory = CreateCompatibleDC(NULL);
SelectObject(hdcMemory, hwndFSWindowBMP);
BitBlt(hdcBackBuffer, x, y, cx, cy, hdcMemory, 0, 0, SRCCOPY);
DeleteDC(hdcMemory);
}
else
{
// Special case for potentially quirky non-GDI drivers
#if 0
// If content is dynamic (updated each frame), always grab the screen copy
// by calling CreateBMPFromWindow to update image held in Bitmap
HDC hdcMemory = CreateCompatibleDC(NULL);
HBITMAP Bitmap = CreateBMPFromWindow(hwndFSWindow);
SelectObject(hdcMemory, Bitmap);
BitBlt(hdcBackBuffer, x, y, cx, cy, hdcMemory, 0, 0, SRCCOPY);
DeleteDC(hdcMemory);
DeleteObject(Bitmap);
#else
// Do a blt directly from the windows screen to the backbuffer
BitBlt(hdcBackBuffer, x, y, cx, cy, hdcScreen, x, y, SRCCOPY);
#endif
}
// Remove clipping region and clean up
SelectClipRgn(hdcBackBuffer, NULL);
DeleteObject(hrgn);
// Now draw the mouse on the backbuffer
MouseCursorCur = GetCursor();
if (MouseCursorCur != MouseCursor)
{
MouseCursor = MouseCursorCur;
GetIconInfo(MouseCursor, &IconInfo);
if (IconInfo.hbmMask)
DeleteObject(IconInfo.hbmMask);
if (IconInfo.hbmColor)
DeleteObject(IconInfo.hbmColor);
}
GetCursorPos(&pt);
pt.x -= IconInfo.xHotspot;
pt.y -= IconInfo.yHotspot;
DrawIcon(hdcBackBuffer, pt.x, pt.y, MouseCursor);
ddBackBuffer->ReleaseDC(hdcBackBuffer);
ReleaseDC(NULL, hdcScreen);
ddFrontBuffer->Flip(NULL, DDFLIP_WAIT);
}
else
{
// GDI hardware
// Update the surface with a blt
ddFrontBuffer->SetClipper(ddClipper);
ddFrontBuffer->Blt(NULL, ddBackBuffer, NULL, DDBLT_WAIT, NULL);
}
}
//-----------------------------------------------------------------------------
// Name: FSWindow_IsActive()
// Desc: Simply checks to see if there's a content window displayed. This check
// should be made prior to calling FSWindow_Update().
//-----------------------------------------------------------------------------
BOOL
FSWindow_IsActive(void)
{
return (hwndFSWindow != NULL);
}
//-----------------------------------------------------------------------------
// Name: FSWindow_IsStatic()
// Desc: Checks to see whether or not the content window needs to be regularly
// updated (its content is dynamic, such as an animation or text entry
// field). A static window is created (an image of the window created
// with a call to CreateBMPFromWindow()) once and used over and over.
//-----------------------------------------------------------------------------
BOOL
FSWindow_IsStatic(void)
{
return (hwndFSWindowBMP != NULL);
}