1125 lines
30 KiB
C++
1125 lines
30 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 );
|
||
|
}
|