/******************************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 ); }