404 lines
13 KiB
C++
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);
|
|
}
|
|
|