windows-nt/Source/XPSP1/NT/multimedia/opengl/toolkits/libmtk/mtkwin.cxx
2020-09-26 16:20:57 +08:00

1125 lines
29 KiB
C++

/******************************Module*Header*******************************\
* Module Name: mtkwin.cxx
*
* Copyright (c) 1996 Microsoft Corporation
*
\**************************************************************************/
#include "mtk.hxx"
#include "glutil.hxx"
#include "mtkwin.hxx"
#include "mtkwproc.hxx"
#include "mtkinit.hxx"
/**************************************************************************\
* MTKWIN constructor
*
\**************************************************************************/
MTKWIN::MTKWIN()
{
Reset();
}
/**************************************************************************\
* Reset
*
* Reset parameters to default init state
\**************************************************************************/
void
MTKWIN::Reset()
{
// Basic initialization
bOwnWindow = FALSE;
wFlags = 0;
hwnd = 0;
hdc = 0;
hrc = 0;
pos.x = pos.y = 0;
size.width = size.height = 0;
pBackBitmap = NULL;
pBackgroundBitmap = NULL;
bDoubleBuf = FALSE;
bFullScreen = FALSE;
execRefCount = 0;
ReshapeFunc = NULL;
RepaintFunc = NULL;
DisplayFunc = NULL;
MouseMoveFunc = NULL;
MouseDownFunc = NULL;
MouseUpFunc = NULL;
KeyDownFunc = NULL;
FinishFunc = NULL;
DataPtr = NULL;
}
/**************************************************************************\
* MTKWIN destructor
*
* This can be called when a window is closed, or by the ss client
*
\**************************************************************************/
MTKWIN::~MTKWIN()
{
//mf: !!! we're in trouble if user calls this directly, because would then need to
// post a DESTROY msg, here putting us in an endless loop...
// -> could have a flag set so we know if user or internal call
//mf: another potential timing problem here : If user calls MTKWIN::Return(),
// which posts an MTK_WM_RETURN msg to the windows queue, and then calls here
// before the msg is processed, we could delete the MTKWIN here before exiting
// the msg loop. So here we should make sure the msg loop is exited by
// calling Return() or something. This should be easy to verify via a
// reference count
if( execRefCount ) {
SS_ERROR1( "MTKWIN::~MTKWIN : execRefCount is %d\n", execRefCount );
// mf: ? can we exit the msg loop here ?
//mf: this din't get through
#if 1
SendMessage( hwnd, MTK_WM_RETURN, 0, 0l );
#else
if( ! PostMessage( hwnd, MTK_WM_RETURN, 0, 0l ) )
SS_ERROR( "MTKWIN dtor : MTK_WM_RETURN msg not posted\n" );
#endif
}
if( pBackBitmap )
delete pBackBitmap;
if( pBackgroundBitmap )
delete pBackgroundBitmap;
if( hwnd ) {
animator.Stop();
// Remove from SSWTable
sswTable.Remove( hwnd );
}
// Clean up GL
//mf: !!!
//mf: This assumes FinishFunc is only related to gl
if( hrc ) {
// FinishFunc still needs gl
if( FinishFunc )
#if 0
(*FinishFunc)( DataPtr );
#else
(*FinishFunc)();
#endif
wglMakeCurrent( NULL, NULL );
if( ! (wFlags & SS_HRC_PROXY_BIT) )
wglDeleteContext( hrc );
}
// Release the dc
if( hdc ) {
HWND hwndForHdc = hwnd;
ReleaseDC(hwndForHdc, hdc);
}
}
/**************************************************************************\
* Create
*
* Create window.
*
\**************************************************************************/
BOOL
MTKWIN::Create( LPCTSTR pszWindowTitle, ISIZE *pSize, IPOINT2D *pPos,
UINT winConfig, WNDPROC userWndProc )
{
HWND hwndParent;
UINT uStyle = 0;
UINT uExStyle = 0;
HINSTANCE hInstance;
int width, height;
if( ! mtk_Init( this ) )
return FALSE;
bOwnWindow = TRUE; // We're creating the window, it's not a wrapper
if( winConfig & MTK_FULLSCREEN ) {
//mf: this really only valid if no border
bFullScreen = TRUE;
pos.x = 0;
pos.y = 0;
size.width = GetSystemMetrics( SM_CXSCREEN );
size.height = GetSystemMetrics( SM_CYSCREEN );
uExStyle |= WS_EX_TOPMOST;
} else {
pos = *pPos;
size = *pSize;
}
LPCTSTR pszClass;
HBRUSH hBrush = ghbrbg;
HCURSOR hCursor = ghArrowCursor;
WNDPROC wndProc;
if( bTransparent = (winConfig & MTK_TRANSPARENT) ) {
uExStyle |= WS_EX_TRANSPARENT;
hBrush = NULL;
}
//mf: if winsize, winpos NULL, pick default size, pos
if( winConfig & MTK_NOBORDER ) {
uStyle |= WS_POPUP;
width = size.width;
height = size.height;
} else {
uStyle |= WS_OVERLAPPEDWINDOW;
/*
* Make window large enough to hold a client area of requested size
*/
RECT WinRect;
//mf: either of these should work
#if 0
WinRect.left = 0;
WinRect.right = size.width;
WinRect.top = 0;
WinRect.bottom = size.height;
#else
WinRect.left = pos.x;
WinRect.right = pos.x + size.width;
WinRect.top = pos.y;
WinRect.bottom = pos.y + size.height;
#endif
AdjustWindowRectEx(&WinRect, uStyle, FALSE, uExStyle );
width = WinRect.right - WinRect.left;
height = WinRect.bottom - WinRect.top;
}
if( winConfig & MTK_NOCURSOR )
hCursor = NULL;
if( userWndProc )
wndProc = userWndProc;
else
wndProc = mtkWndProc;
// Register window class
pszClass = mtk_RegisterClass( wndProc, NULL, hBrush, hCursor );
hInstance = GetModuleHandle( NULL );
hwndParent = NULL; // for now
hwnd = CreateWindowEx(
uExStyle,
pszClass,
pszWindowTitle,
uStyle,
pos.x,
pos.y,
width,
height,
hwndParent,
NULL, // menu
hInstance,
(LPVOID) this
);
if (!hwnd) {
SS_WARNING( "SSW::CreateSSWindow : CreateWindowEx failure\n" );
return FALSE;
}
if( bTransparent ) {
// Create a bitmap buffer that tracks the window size. This will be
// used to store a window background.
ConfigureForGdi();
pBackgroundBitmap = new MTKBMP( hdc );
if( !pBackgroundBitmap ) {
SS_WARNING( "MTKWIN::Create: couldn't create background bitmap\n" );
} else {
// Set bitmap's size to the window's size
pBackgroundBitmap->Resize( &size );
}
}
animator.SetHwnd( hwnd );
ShowWindow(hwnd, SW_SHOW);
return TRUE;
}
/**************************************************************************\
* ConfigureForGdi
*
* Creates an hdc for the window
*
\**************************************************************************/
BOOL
MTKWIN::ConfigureForGdi()
{
if( hdc )
// already configured
return TRUE;
// Figure window to get hdc from
#if 0
HWND hwndForHdc = hwnd ? hwnd : psswParent ? psswParent->hwnd : NULL;
#else
HWND hwndForHdc = hwnd;
#endif
if( !hwndForHdc || !(hdc = GetDC(hwndForHdc)) ) {
SS_WARNING( "SSW::ConfigureForGdi failed\n" );
return FALSE;
}
return TRUE;
}
/**************************************************************************\
* ConfigureForGL
*
* Creates a GL rendering context for the specified window
*
\**************************************************************************/
BOOL
MTKWIN::Config( UINT glConfig )
{
return Config( glConfig, NULL );
}
BOOL
MTKWIN::Config( UINT glConfig, PVOID pConfigData )
{
if( hrc )
// Already configured...
return TRUE;
if( ConfigureForGdi() &&
(hrc = hrcSetupGL( glConfig, pConfigData )) )
return TRUE;
SS_WARNING( "SSW::ConfigureForGL failed\n" );
return FALSE;
}
/**************************************************************************\
* hrcSetupGL
*
* Setup OpenGL.
*
\**************************************************************************/
#define NULL_RC ((HGLRC) 0)
HGLRC
MTKWIN::hrcSetupGL( UINT glConfig, PVOID pData )
{
HGLRC hrc;
HDC hgldc;
int pfFlags = 0;
PIXELFORMATDESCRIPTOR pfd = {0};
// Setup pixel format flags
// Double buffering can either be done with a double-buffered pixel
// format, or by using a local back buffer bitmap that tracks the window
// size. The latter allows us more control with buffer swaps.
bDoubleBuf = glConfig & MTK_DOUBLE;
BOOL bBitmapBackBuf = glConfig & MTK_BITMAP;
if( bDoubleBuf ) {
if( bBitmapBackBuf )
pfFlags |= SS_BITMAP_BIT;
else
pfFlags |= SS_DOUBLEBUF_BIT;
}
if( glConfig & MTK_DEPTH )
pfFlags |= SS_DEPTH32_BIT;
if( glConfig & MTK_DEPTH16 )
pfFlags |= SS_DEPTH16_BIT;
if( glConfig & MTK_ALPHA )
pfFlags |= SS_ALPHA_BIT;
// If preview mode or config mode, don't allow pixel formats that need
// the system palette, as this will create much ugliness.
if( !bFullScreen )
pfFlags |= SS_NO_SYSTEM_PALETTE_BIT;
//mf: don't really need pixel format for window if using back bitmap method,
// but if user wants to draw to front buffer, then we'll need it. So, we'll
// always set it here.
if( !SSU_SetupPixelFormat( hdc, pfFlags, &pfd ) )
return NULL_RC;
//mf: ???
// Update pfFlags based on pfd returned
// !!! mf: klugey, fix after SUR
// (for now, the only ones we care about are the generic/accelerated flags)
if( (pfd.dwFlags & (PFD_GENERIC_FORMAT|PFD_GENERIC_ACCELERATED))
== PFD_GENERIC_FORMAT )
pfFlags |= SS_GENERIC_UNACCELERATED_BIT;
if( SSU_bNeedPalette( &pfd ) ) {
// Note: even if bStretch, need to set up palette here so they match
if( !gpssPal ) {
SS_PAL *pssPal;
#if 1
BOOL bTakeOverPalette = bFullScreen ? TRUE : FALSE;
#else
//mf: For next rev, we don't have to force palette takeover - but it will
// automically be invoked for any case like MCD, etc.
BOOL bTakeOverPalette = FALSE;
#endif
// The global palette has not been created yet - do it
// SS_PAL creation requires pixel format descriptor for color bit
// information, etc. (the pfd is cached in SS_PAL, since for
// palette purposes it is the same for all windows)
pssPal = new SS_PAL( hdc, &pfd, bTakeOverPalette );
if( !pssPal )
return NULL_RC;
// Set approppriate palette manage proc
if( bFullScreen )
pssPal->paletteManageProc = FullScreenPaletteManageProc;
else
// use regular palette manager proc
pssPal->paletteManageProc = PaletteManageProc;
gpssPal = pssPal;
}
// Realize the global palette in this window
//mf: assume we're realizing in foreground
HWND hwndPal = hwnd;
if( hwndPal )
gpssPal->Realize( hwndPal, hdc, FALSE );
}
if( bBitmapBackBuf ) {
pBackBitmap = new MTKBMP( hdc );
if( !pBackBitmap ) {
SS_WARNING( "MTKWIN::hrcSetupGL : couldn't create back bitmap\n" );
return NULL_RC;
}
// Set bitmap's size to the window's size
pBackBitmap->Resize( &size );
hgldc = pBackBitmap->hdc;
// Setup pixelformat
if( !SSU_SetupPixelFormat( hgldc, pfFlags, &pfd ) )
return NULL_RC;
// If window needed a palette, so does the bitmap...
if( gpssPal )
SSDIB_UpdateColorTable( hgldc, hdc, gpssPal->hPal );
} else {
hgldc = hdc;
}
// Create a new hrc
hrc = wglCreateContext(hgldc);
if( !hrc || !wglMakeCurrent(hgldc, hrc) ) {
SS_WARNING( "SSW::hrcSetupGL : hrc context failure\n" );
return NULL_RC;
}
SS_DBGLEVEL2( SS_LEVEL_INFO,
"SSW::hrcSetupGL: wglMakeCurrent( hrc=0x%x, hwnd=0x%x )\n", hrc, hwnd );
//mf: Note that these queries are based on a single gl window screen saver. In
// a more complicated scenario, these capabilities could be queried on a
// per-window basis (since support could vary with pixel formats).
gGLCaps.Query();
// Send another reshape msg to the app, since the first one on window
// create would have been sent before we had an rc
Reshape();
return hrc;
}
/**************************************************************************\
* MakeCurrent
*
* Call wglMakeCurrent for this window's hrc. Note: an ss client may have
* more than one hrc (e.g. pipes), in which case it is the client's
* responsibility to make current.
\**************************************************************************/
void
MTKWIN::MakeCurrent()
{
if( ! wglMakeCurrent( hdc, hrc ) )
SS_WARNING( "SSW::MakeCurrent : wglMakeCurrent failure\n" );
}
// Callback functions:
/******************************Public*Routine******************************\
* ss_ReshapeFunc
*
\**************************************************************************/
void
MTKWIN::SetReshapeFunc(MTK_RESHAPEPROC Func)
{
ReshapeFunc = Func;
}
/******************************Public*Routine******************************\
* ss_RepaintFunc
*
\**************************************************************************/
void
MTKWIN::SetRepaintFunc(MTK_REPAINTPROC Func)
{
RepaintFunc = Func;
}
void
MTKWIN::SetDisplayFunc(MTK_DISPLAYPROC Func)
{
DisplayFunc = Func;
}
/******************************Public*Routine******************************\
* SetAnimateFunc
*
\**************************************************************************/
void
MTKWIN::SetAnimateFunc(MTK_ANIMATEPROC Func )
{
animator.SetFunc( Func );
// If we are in msg loop and Func is non-NULL, have to make sure
// animator starts again... (awkward). If animator was already started,
// this will do nothing
if( execRefCount && Func )
animator.Start();
}
/******************************Public*Routine******************************\
* Animate
*
* Call the animation function
*
* If animate mode is interval (as opposed to continuous),
* animate the number of supplied frames. The animation count is decremented
* by the WndProc processing the WM_TIMER messages. Exits the msg loop when
* the desired number fo frames has been animated.
*
\**************************************************************************/
//mf: had to rename from Animate to mtkAnimate due to name conflicts at link
// time
void
MTKWIN::mtkAnimate()
{
if( ! animator.Draw() )
Return();
}
/******************************Public*Routine******************************\
* SetAnimateMode
*
*
\**************************************************************************/
void
MTKWIN::SetAnimateMode( UINT mode, float *fParam )
{
animator.SetMode( mode, fParam );
}
/******************************Public*Routine******************************\
* Exec
*
* Starts the message loop for the window.
*
* If an animation has been requested prior to this call, then a new animation
* timer is setup. This msg loop can terminate in the following ways :
* 1) The window is closed
* 2) An interval animation was requested, and the required number of frames
* have been drawn
* 3) The user calls MTKWIN::Return(), which will cause the MTKWIN::Exec()
* call to return
*
* For now :
* Returns TRUE on normal termination, FALSE if the window it's animating in
* gets closed.
*
\**************************************************************************/
BOOL
MTKWIN::Exec()
{
// If user is already in here, get out
if( execRefCount )
return TRUE;
execRefCount++;
// Stop any existing timer (this will flush WM_TIMER msg's)
animator.Stop();
// Start new animation timer (if animator modes are set)
animator.Start();
MSG msg;
BOOL bNotQuitMsg;
while( bNotQuitMsg = GetMessage( &msg, hwnd, 0, 0 ) )
{
if( msg.message == MTK_WM_RETURN ) {
// User or mtk wants to terminate msg loop and return control
// (mf: could pick up return parameter here...)
// SS_DBGPRINT1( "MTKWIN::Exec got WM_RETURN for %p\n", this );
break;
}
//mf: ? better way of doing this ?
else if( ! msg.hwnd ) {
// Window has been destroyed, get out !
SS_DBGPRINT( "MTKWIN::Exec : hwnd = 0, forcing msg loop exit\n" );
return FALSE;
}
TranslateMessage( &msg );
DispatchMessage( &msg );
}
animator.Stop();
execRefCount--;
if( bNotQuitMsg )
return TRUE;
else {
SS_DBGPRINT1( "MTKWIN::Exec got WM_QUIT for %p\n", this );
return FALSE;
}
}
/******************************Public*Routine******************************\
* Return
*
* Called by the user when they want to return from the Exec() call which
* started the message loop.
*
* mf: could include parameter here
*
\**************************************************************************/
void
MTKWIN::Return()
{
animator.Stop();
PostMessage( hwnd, MTK_WM_RETURN, 0, 0l );
}
void
MTKWIN::SetMouseMoveFunc(MTK_MOUSEMOVEPROC Func)
{
MouseMoveFunc = Func;
}
void
MTKWIN::SetMouseUpFunc(MTK_MOUSEUPPROC Func)
{
MouseUpFunc = Func;
}
void
MTKWIN::SetMouseDownFunc(MTK_MOUSEDOWNPROC Func)
{
MouseDownFunc = Func;
}
void
MTKWIN::SetKeyDownFunc(MTK_KEYDOWNPROC Func)
{
KeyDownFunc = Func;
}
void
MTKWIN::GetMouseLoc( int *x, int *y )
{
POINT Point;
*x = 0;
*y = 0;
GetCursorPos(&Point);
/*
* GetCursorPos returns screen coordinates,
* we want window coordinates
*/
*x = Point.x - pos.x;
*y = Point.y - pos.y;
}
void
MTKWIN::Close()
{
DestroyWindow( hwnd );
}
/******************************Public*Routine******************************\
* ss_FinishFunc
*
\**************************************************************************/
void
MTKWIN::SetFinishFunc(MTK_FINISHPROC Func)
{
FinishFunc = Func;
}
/**************************************************************************\
* Resize
*
* Resize wrapper
*
* Called in response to WM_SIZE.
*
\**************************************************************************/
void
MTKWIN::Resize( int width, int height )
{
size.width = width;
size.height = height;
if( pBackBitmap )
pBackBitmap->Resize( &size );
if( pBackgroundBitmap )
pBackgroundBitmap->Resize( &size );
Reshape();
}
/**************************************************************************\
* Repaint
*
* Repaint wrapper
*
* Called in response to WM_PAINT.
*
\**************************************************************************/
#define NULL_UPDATE_RECT( pRect ) \
( ((pRect)->left == 0) && \
((pRect)->right == 0) && \
((pRect)->top == 0) && \
((pRect)->bottom == 0) )
void
MTKWIN::Repaint( BOOL bCheckUpdateRect )
{
if( !hwnd )
return;
RECT rect, *pRect = NULL;
if( bCheckUpdateRect ) {
GetUpdateRect( hwnd, &rect, FALSE );
//mf
SS_DBGPRINT4( "MTKWIN::Repaint rect: %d - %d, %d - %d\n", rect.left, rect.right,
rect.top, rect.bottom );
// mf: Above supposed to return NULL if rect is all 0's,
// but this doesn't happen
if( NULL_UPDATE_RECT( &rect ) )
return;
pRect = ▭
}
// transparent window thing
if( pBackgroundBitmap ) {
if( !pRect ) {
// UpdateBg doesn't handle null rect
pRect = ▭
GetClientRect( hwnd, pRect );
}
UpdateBackgroundBitmap( pRect );
}
#if 0
if( RepaintFunc )
(*RepaintFunc)( pRect );
#else
#if 0
Display();
#else
//mf: test: ? help bg update problem ?? nope, din't seem to...
MSG Message;
if (!PeekMessage(&Message, hwnd, MTK_WM_REDRAW, MTK_WM_REDRAW, PM_NOREMOVE) )
{
PostMessage( hwnd, MTK_WM_REDRAW, 0, 0l );
}
#endif
#endif
}
void
MTKWIN::Display()
{
if( DisplayFunc )
(*DisplayFunc)();
}
//mf: not using these in current scheme, although might if use 'ss' mode
#if 0
/**************************************************************************\
* UpdateWindow
*
* Update the window
*
* Currently this assumes all windows are being animated (i.e. not showing
* a static image)
*
* Things *must* happen in the order defined here, so they work on generic as
* well as hardware implementations.
* Note: Move must happen after SwapBuf, and will cause some encroaching on
* the current display, as the parent window repaints after the move. Therefore
* apps must take care to leave an empty border around their rendered image,
* equal to the maximum window move delta.
*
\**************************************************************************/
void
MTKWIN::UpdateWindow()
{
if( !AnimateFunc )
return;
// bDoubleBuf and pStretch should be mutually exclusive...
if( bDoubleBuf ) {
UpdateDoubleBufWin();
} else {
//mf: ? where's the clearing here ? (true, no one uses this path...)
#if 0
(*AnimateFunc)( DataPtr );
#else
(*AnimateFunc)();
#endif
}
}
/**************************************************************************\
* UpdateDoubleBufWin
*
* This is used when moving a double buffered window around. It will
* work for all configurations.
*
\**************************************************************************/
void
MTKWIN::UpdateDoubleBufWin()
{
RECT updateRect;
// Update the back buffer
#if 0
(*AnimateFunc)( DataPtr );
#else
(*AnimateFunc)();
#endif
// Swap to the new window position
SwapBuffers( hdc );
}
#endif
/**************************************************************************\
* GetSSWindowRect
*
* Return window position and size in supplied RECT structure
*
* - This rect is relative to the parent
\**************************************************************************/
void
MTKWIN::GetSSWindowRect( LPRECT lpRect )
{
lpRect->left = pos.x;
lpRect->top = pos.y;
lpRect->right = pos.x + size.width;
lpRect->bottom = pos.y + size.height;
}
/**************************************************************************\
* GLPosY
*
* Return y-coord of window position in GL coordinates (a win32 window position
* (starts from top left, while GL starts from bottom left)
*
\**************************************************************************/
int
MTKWIN::GLPosY()
{
//mf: !!!
#if 0
return psswParent->size.height - size.height - pos.y;
#else
return 0;
#endif
}
/**************************************************************************\
* SwapBuffers
*
\**************************************************************************/
//mf: name problem...
void
MTKWIN::mtkSwapBuffers()
{
if( bDoubleBuf ) {
if( pBackBitmap )
CopyBackBuffer();
else
SwapBuffers( hdc );
}
}
/**************************************************************************\
*
*
\**************************************************************************/
void
MTKWIN::Flush()
{
glFlush();
if( bDoubleBuf ) {
mtkSwapBuffers();
}
}
/**************************************************************************\
* CopyBackBuffer
*
* Like SwapBuffers, but copies from local bitmap to front buffer
*
* Also capable of copying over 1 or more rects of the bitmap, rather than the
* whole thing. mf: Might need local implementation of swaphintrect here, to
* collect and reduce the rects
\**************************************************************************/
void
MTKWIN::CopyBackBuffer()
{
if( !pBackBitmap )
return;
// Do a BitBlt from back buffer to the window (may as well put stretch in
// here ?
if( (size.width == pBackBitmap->size.width) &&
(size.height == pBackBitmap->size.height) ) // buffers same size
{
BitBlt(hdc, 0, 0, size.width, size.height,
pBackBitmap->hdc, 0, 0, SRCCOPY);
}
else
{
SS_WARNING( "MTKWIN::CopyBackBuffer: bitmap size mismatch\n" );
StretchBlt(hdc, 0, 0,
size.width, size.height,
pBackBitmap->hdc, 0, 0,
pBackBitmap->size.width, pBackBitmap->size.height,
SRCCOPY);
}
GdiFlush();
}
/**************************************************************************\
* UpdateBackgroundBitmap
*
* Updates the background bitmap with screen bits
*
\**************************************************************************/
void
MTKWIN::UpdateBackgroundBitmap( RECT *pRect )
{
if( !pBackgroundBitmap ) {
SS_WARNING( "MTKWIN::UpdateBackgroundBitmap : No background bitmap\n" );
return;
}
// mf:!!! handle update rect parameter
MTKBMP *pBmpDest = pBackgroundBitmap;
// Get a screen DC
HDC hdcScreen = GetDC( NULL );
#if DBG
if( !hdcScreen ) {
SS_WARNING( "MTKWIN::UpdateBackgroundBitmap : failed to get screen hdc\n" );
return;
}
#endif
//mf
#if 0
SS_DBGPRINT4( "MTKWIN::UpdateBackgroundBitmap : %d - %d, %d - %d\n", pRect->left, pRect->right,
pRect->top, pRect->bottom );
#endif
// Calc the screen origin of the window
RECT screenRect = {0, 0 }; // just need left and top points
MapWindowPoints( hwnd, NULL, (POINT *) &screenRect, 2 );
// Offset screenRect with the supplied rect
screenRect.left += pRect->left;
screenRect.top += pRect->top;
// Set update size
//mf: thought I should have to add 1 here, but I guess pRect is non-inclusive...
ISIZE updateSize = { pRect->right - pRect->left,
pRect->bottom - pRect->top };
if( (size.width == pBmpDest->size.width) &&
(size.height == pBmpDest->size.height) ) // buffers same size
{
BitBlt(pBmpDest->hdc,
pRect->left, pRect->top,
updateSize.width, updateSize.height,
hdcScreen,
screenRect.left, screenRect.top, SRCCOPY);
}
else
{
#if 0
//mf: ignore this for now
// Shouldn't happen, since BackgroundBitmap tracks window size
StretchBlt(pBmpDest->hdc, 0, 0,
pBmpDest->size.width, pBmpDest->size.height,
hdcScreen, screenRect.left, screenRect.top,
size.width, size.height,
SRCCOPY);
#else
SS_WARNING( "MTKWIN::UpdateBackgroundBitmap : bitmap size mismatch\n" );
#endif
}
GdiFlush();
}
/**************************************************************************\
* ClearToBackground
*
* Copy from the background bitmap to the window. If the window is doublebuf,
* then we copy to the backbuffer instead of the window.
*
\**************************************************************************/
void
MTKWIN::ClearToBackground()
{
if( !pBackgroundBitmap ) {
SS_WARNING( "MTKWIN::ClearToBackgournd : No background bitmap\n" );
return;
}
MTKBMP *pBmpSrc = pBackgroundBitmap;
HDC hdcDest;
if( bDoubleBuf ) {
if( !pBackBitmap )
return;
//mf: assumption here that backbitmap size is same as window
hdcDest = pBackBitmap->hdc;
} else
hdcDest = hdc;
if( (size.width == pBmpSrc->size.width) &&
(size.height == pBmpSrc->size.height) ) // buffers same size
{
BitBlt(hdcDest, 0, 0, size.width, size.height,
pBmpSrc->hdc, 0, 0, SRCCOPY);
}
else
{
StretchBlt(hdcDest, 0, 0,
size.width, size.height,
pBmpSrc->hdc, 0, 0,
pBmpSrc->size.width, pBmpSrc->size.height,
SRCCOPY);
}
GdiFlush();
}
/**************************************************************************\
* Reshape
*
* Reshape wrapper
* Sends reshape msg to screen saver
* This is the size of the surface that gl renders onto, which can be a bitmap.
*
\**************************************************************************/
void
MTKWIN::Reshape()
{
// Point to size of window, or bitmap if it has one
ISIZE *pSize = &size;
// If the window has an hrc, set default viewport
//mf: so app doesn't have to worry about it ?
if( hrc ) {
glViewport( 0, 0, pSize->width, pSize->height );
}
if( ReshapeFunc ) {
#if 0
(*ReshapeFunc)( pSize->width, pSize->height, DataPtr );
#else
(*ReshapeFunc)( pSize->width, pSize->height );
#endif
}
}
/******************************Public*Routine******************************\
* GdiClear
*
* Clears window using Gdi FillRect
\**************************************************************************/
void
MTKWIN::GdiClear()
{
if( !hdc )
return;
RECT rect;
GetClientRect( hwnd, &rect );
//mf: rect is exclusive, so shouldn't we have to add 1 ?
FillRect( hdc, &rect, ghbrbg );
GdiFlush();
}
//mf: unicode...
void
MTKWIN::SetTitle( char *title )
{
SetWindowText( hwnd, title );
}