|
|
/******************************Module*Header*******************************\
* Module Name: sswindow.cxx * * Copyright (c) 1996 Microsoft Corporation * \**************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include "scrnsave.h"
#include "glscrnsv.h"
#include "ssintrnl.hxx"
#include "sswindow.hxx"
#include "ssutil.hxx"
static void (__stdcall *glAddSwapHintRect)(GLint, GLint, GLint, GLint);
// externs from ssinit.cxx
extern void *gDataPtr; extern void (*gReshapeFunc)(int, int, void *); extern void (*gRepaintFunc)( LPRECT, void *); extern void (*gUpdateFunc)( void *); extern void (*gInitFunc)( void *); extern void (*gFinishFunc)( void *); extern void (*gFloaterBounceFunc)( void *);
// forwards
static void GetWindowSize( HWND hwnd, ISIZE *pSize ); static void ss_QueryAddSwapHintRect(); static void DrawGdiDeltaRect( HDC hdc, HBRUSH hbr, RECT *pRect1, RECT *pRect2 ); static void DrawGLDeltaRect( GLRECT *pRect1, GLRECT *pRect2 );
/**************************************************************************\
* SSW constructor * \**************************************************************************/
SSW::SSW( PSSW psswParentArg, ISIZE *pSize, IPOINT2D *pPos, BOOL bMotion, SSCHILDSIZEPROC ChildSizeFuncArg ) { // Basic initialization
Reset();
// Initialization based on constructor parameters
psswParent = psswParentArg;
ChildSizeFunc = ChildSizeFuncArg;
if( pSize ) size = *pSize; if( pPos ) pos = *pPos; else pos.x = pos.y = 0;
if( bMotion && psswParent ) { // Allocate motion structure
pMotion = (MOTION *) LocalAlloc( LMEM_ZEROINIT | LMEM_FIXED, sizeof(MOTION) ); // If pMotion is NULL, then motion is disabled
}
// Call back to the client screen saver to determine size and motion
// characteristics of child based on its parent size.
GetChildInfo(); // this can set pos and size
if( pMotion ) { if( pPos == NULL ) { // Set a random window pos
pos.x = ss_iRand2( 0, (psswParent->size.width - size.width) ); pos.y = ss_iRand2( 0, (psswParent->size.height - size.height) );
// Set the motion parameters
ResetMotion(); } // Have to make sure parent has an hdc so it can draw background when
// this child moves
if( !psswParent->hdc ) psswParent->hdc = GetDC( psswParent->hwnd ); }
if( psswParent ) { // Need to add this pssw to its parent's list
psswParent->AddChild( this ); // Default is to be subWindow of parent
psswParent->iSubWindow++; // increment reference count
} }
/**************************************************************************\
* SSW constructor * * Used when wrapping an SSW around an already existing window * (as when drawing GL on dialog buttons) \**************************************************************************/
SSW::SSW( PSSW psswParentArg, HWND hwndArg ) { Reset();
psswParent = psswParentArg; if( psswParent ) // Need to add this pssw to its parent's list
psswParent->AddChild( this );
hwnd = hwndArg; if( !hwnd ) { SS_ERROR( "SSW::SSW : NULL hwnd\n" ); return; }
bOwnWindow = FALSE; // Get the window size
GetWindowSize( hwnd, &size );
gpss->sswTable.Register( hwnd, this ); }
/**************************************************************************\
* Reset * * Reset parameters to default init state \**************************************************************************/
void SSW::Reset() { // Basic initialization
bOwnWindow = TRUE; iSubWindow = 0; bValidateBg = FALSE; wFlags = 0; hwnd = 0; hdc = 0; hrc = 0; pos.x = pos.y = 0; size.width = size.height = 0; psswParent = NULL; psswSibling = NULL; psswChildren = NULL; bDoubleBuf = FALSE; pStretch = NULL; pMotion = NULL; pGLc = NULL;
InitFunc = NULL; UpdateFunc = NULL; ReshapeFunc = NULL; RepaintFunc = NULL; FloaterBounceFunc = NULL; FinishFunc = NULL; ChildSizeFunc = NULL; DataPtr = NULL; }
/**************************************************************************\
* SSW destructor * * This can be called when a window is closed, or by the ss client * \**************************************************************************/
SSW::~SSW() { // If this window has any children, they will have to be terminated too
if( psswChildren ) { PSSW psswChild = psswChildren; while( psswChild ) { // Delete first child in list
if( psswChild->hwnd && bOwnWindow ) { // We created this window, we must destroy it
DestroyWindow( psswChild->hwnd ); } else { delete psswChild; } // Next child is now first child in list
psswChild = psswChildren; } }
if( psswParent ) // Need to remove this pssw from its parent's list
psswParent->RemoveChild( this );
if( hwnd ) { // Remove from SSWTable
gpss->sswTable.Remove( hwnd ); } else { // subWindow
if( psswParent ) { SS_ASSERT1( (psswParent->iSubWindow > 0), "Invalid subWindow reference count for pssw=0x%x\n", this ); psswParent->iSubWindow--; // decrement subWindow reference count
} }
// Clean up GL
if( hrc ) { // FinishFunc still needs gl
if( FinishFunc ) (*FinishFunc)( DataPtr );
wglMakeCurrent( NULL, NULL ); if( ! (wFlags & SS_HRC_PROXY_BIT) ) wglDeleteContext( hrc ); }
// Clean up any bitmaps
if( pStretch ) { SS_BITMAP *pssbm = &pStretch->ssbm;
DeleteObject(SelectObject(pssbm->hdc, pssbm->hbmOld)); DeleteDC(pssbm->hdc); }
// Release the dc
if( hdc ) { HWND hwndForHdc = hwnd ? hwnd : psswParent ? psswParent->hwnd : NULL; ReleaseDC(hwndForHdc, hdc); } }
/**************************************************************************\
* AddChild * * Add the supplied child SSW to this SSW. \**************************************************************************/
void SSW::AddChild( PSSW psswChild ) { if( !psswChildren ) { psswChildren = psswChild; return; }
// Else travel along the sibling chain of psswChildren and deposit
// psswChild at the end
PSSW pssw = psswChildren; while( pssw->psswSibling ) pssw = pssw->psswSibling; pssw->psswSibling = psswChild; }
/**************************************************************************\
* RemoveChild * * Remove this child from the parent's list * * Whoever calls this needs to update SSW_TABLE too... \**************************************************************************/
BOOL SSW::RemoveChild( PSSW psswChild ) { if( !psswChildren ) { // Something wrong - this window has no children
SS_ERROR( "SSW::RemoveChild : no children\n" ); return FALSE; }
PSSW psswPrev; PSSW pssw = psswChildren;
while( pssw != NULL ) { if( pssw == psswChild ) { // found it !
if( psswChild == psswChildren ) // The child being removed is the first in the list
psswChildren = psswChild->psswSibling; else psswPrev->psswSibling = pssw->psswSibling; return TRUE; } // Move up the pointers
psswPrev = pssw; pssw = psswPrev->psswSibling; }
SS_ERROR( "SSW::RemoveChild : child not found\n" ); return FALSE; }
/**************************************************************************\
* GetWindowSize * \**************************************************************************/
static void GetWindowSize( HWND hwnd, ISIZE *pSize ) { RECT clientRect;
GetClientRect( hwnd, &clientRect );
pSize->width = clientRect.right - clientRect.left + 1; pSize->height = clientRect.bottom - clientRect.top + 1; }
/**************************************************************************\
* CreateSSWindow * * Create OpenGL floater window. This window floats on top of the screen * saver window, bouncing off each of the screen edges. * * History * Apr. 28, 95 : [marcfo] * - Floater motion characteristics now defined by caller * Aug. 14, 95 : [marcfo] * - Position the window offscreen initially, to workaround a win95 bug * with a corrupted initial clip rect. * \**************************************************************************/
BOOL SSW::CreateSSWindow(HINSTANCE hMainInstance, UINT uStyle, UINT uExStyle , LPCTSTR pszWindowTitle, WNDPROC wndProcArg, LPCTSTR pszClassName, HWND hwndParentOverride ) { IPOINT2D startPos; HWND hwndParent;
if( hwndParentOverride ) hwndParent = hwndParentOverride; else hwndParent = psswParent ? psswParent->hwnd : NULL;
wndProc = wndProcArg;
if( !pMotion ) startPos = pos; else { // Initialize start position off screen to work around win95 screen
// validation bug
startPos.x = pos.x - psswParent->size.width; startPos.y = pos.y - psswParent->size.height; }
hwnd = CreateWindowEx( uExStyle, pszClassName, pszWindowTitle, uStyle, startPos.x, startPos.y, size.width, // width
size.height, // height
hwndParent, NULL, // menu
hMainInstance, (LPVOID) this );
if (!hwnd) { //mf: could still continue here by using sub-windows
SS_WARNING( "SSW::CreateSSWindow : CreateWindowEx failure\n" ); return FALSE; }
// This window is on its own now
if( psswParent ) { SS_ASSERT1( (psswParent->iSubWindow > 0), "Invalid subWindow reference count for pssw=0x%x\n", this ); psswParent->iSubWindow--; // decrement subWindow reference count
}
ShowWindow(hwnd, SW_SHOW);
return TRUE; }
/**************************************************************************\
* GetChildInfo * * Call the window's ChildSizeFunc \**************************************************************************/
void SSW::GetChildInfo( ) { if( !ChildSizeFunc ) return;
CHILD_INFO childInfo;
// Call the client's SizeFunc to get required info
(*ChildSizeFunc)( &psswParent->size, &childInfo );
// Pull required values into pssw and validate them
size = childInfo.size; ValidateChildSize();
if( !pMotion ) { pos = childInfo.pos; bValidateChildPos(); } else { pMotion->posInc = childInfo.motionInfo.posInc; pMotion->posIncVary = childInfo.motionInfo.posIncVary; pMotion->posIncCur = pMotion->posInc; } }
/**************************************************************************\
* ConfigureForGdi * * Creates an hdc for the window * \**************************************************************************/
BOOL SSW::ConfigureForGdi() { if( hdc ) // already configured
return TRUE;
// Figure window to get hdc from
HWND hwndForHdc = hwnd ? hwnd : psswParent ? psswParent->hwnd : NULL;
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 SSW::ConfigureForGL( SS_GL_CONFIG *pGLcArg ) { pGLc = pGLcArg; return ConfigureForGL(); }
BOOL SSW::ConfigureForGL() { if( hrc ) // Already configured...
return TRUE;
if( ConfigureForGdi() && (hrc = hrcSetupGL()) ) return TRUE;
SS_WARNING( "SSW::ConfigureForGL failed\n" ); return FALSE; }
/**************************************************************************\
* hrcSetupGL * * Setup OpenGL. * \**************************************************************************/
#define NULL_RC ((HGLRC) 0)
HGLRC SSW::hrcSetupGL() { if( !pGLc ) return NULL_RC;
//mf: This routine does not yet fully support logical sub-windows...
HGLRC hrc; HDC hgldc; int pfFlags = pGLc->pfFlags; PIXELFORMATDESCRIPTOR pfd = {0};
pStretch = pGLc->pStretch; if( pStretch ) { if( NeedStretchedWindow() ) { // Only need single buffered pixel format
pfFlags &= ~SS_DOUBLEBUF_BIT; pfFlags |= SS_BITMAP_BIT; // yup, BOTH window and bitmap need this
} else // Turn off stretching
pStretch = NULL; }
// If preview mode or config mode, don't allow pixel formats that need
// the system palette, as this will create much ugliness.
if( ss_fPreviewMode() || ss_fConfigMode() ) pfFlags |= SS_NO_SYSTEM_PALETTE_BIT;
// If config mode, force a non-accelerated pixel format, as WNDOBJ's
// seem to have problems with MCD, ICD. Do the same thing if a
// monitor configuration is detected, since only the generic implementation
// will work properly in this case on all displays.
if( ss_fConfigMode() || (GetSystemMetrics(SM_CMONITORS) > 1) ) pfFlags |= SS_GENERIC_UNACCELERATED_BIT;
bDoubleBuf = SS_HAS_DOUBLEBUF( pfFlags );
if( !SSU_SetupPixelFormat( hdc, pfFlags, &pfd ) ) return NULL_RC;
// Update pGLc->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 ) pGLc->pfFlags |= SS_GENERIC_UNACCELERATED_BIT;
if( SSU_bNeedPalette( &pfd ) ) { // Note: even if bStretch, need to set up palette here so they match
if( !gpss->pssPal ) { SS_PAL *pssPal; BOOL bTakeOverPalette = ss_fFullScreenMode() ? TRUE : FALSE;
// 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( ss_fFullScreenMode() ) pssPal->paletteManageProc = FullScreenPaletteManageProc; else // use regular palette manager proc
pssPal->paletteManageProc = PaletteManageProc; gpss->pssPal = pssPal; } // Realize the global palette in this window
//mf: assume we're realizing in foreground
HWND hwndPal = hwnd ? hwnd : psswParent ? psswParent->hwnd : NULL; if( hwndPal ) gpss->pssPal->Realize( hwndPal, hdc, FALSE ); }
if( pStretch ) { // Stretch blt mode: For every frame, we'll be doing a StretchBlt
// from a DIB to the screen. Need to set up a compatible memdc.
SS_BITMAP *pssbm;
pssbm = &pStretch->ssbm;
pssbm->hdc = CreateCompatibleDC(hdc); if( !pssbm->hdc ) return NULL_RC; ResizeStretch(); // this creates the DIB Section
pfFlags = 0; pfFlags |= SS_BITMAP_BIT; if( !SSU_SetupPixelFormat( pssbm->hdc, pfFlags, &pfd ) ) { return NULL_RC; } //mf: this ppfd's palette bits must match the window's !!
// If window needs palette, so does bitmap...
if( gpss->pssPal ) { SS_PAL *pssPal = gpss->pssPal; extern void ssw_UpdateDIBColorTable( HDC, HDC );
ssw_UpdateDIBColorTable( pssbm->hdc, hdc ); } hgldc = pssbm->hdc; } else { hgldc = hdc; }
if( pGLc->hrc ) { // Use the supplied hrc
hrc = pGLc->hrc; // Set flag so we don't delete this borrowed hrc when the SSW terminates
wFlags |= SS_HRC_PROXY_BIT; } else // Create a new hrc
hrc = wglCreateContext(hgldc);
if( !hrc || !wglMakeCurrent(hgldc, hrc) ) { SS_WARNING( "SSW::hrcSetupGL : hrc context failure\n" ); return NULL_RC; }
if( !hwnd && (bDoubleBuf || pStretch) ) {
// enable scissoring
glEnable( GL_SCISSOR_TEST );
if( !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) ) { // MCD or ICD, possible hardware implementation - we maintain
// a lastRect to handle SwapBuffer issues
lastRect.x = lastRect.y = lastRect.width = lastRect.height = 0; } }
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).
// Query the GL version - sets support for any new (e.g. 1.1) functionality
ss_QueryGLVersion();
// Query paletted texture extension
ss_QueryPalettedTextureEXT();
// Query the AddSwapHintRect WIN extension
ss_QueryAddSwapHintRect();
// Pull in any Func's that were already defined (for compatibility with
// old mechanism)
InitFunc = gInitFunc; UpdateFunc = gUpdateFunc; ReshapeFunc = gReshapeFunc; RepaintFunc = gRepaintFunc; FloaterBounceFunc = gFloaterBounceFunc; FinishFunc = gFinishFunc; DataPtr = gDataPtr;
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 SSW::MakeCurrent() { if( ! wglMakeCurrent( hdc, hrc ) ) { SS_WARNING( "SSW::MakeCurrent : wglMakeCurrent failure\n" ); } }
/**************************************************************************\
* InitGL * * Call the window's GL Init Func * * Priority is raised to expedite any initialization (e.g. loading and * processing textures can take a while. * * A Reshape msg is sent to the client ss, as this is required for setting * glViewport, etc. \**************************************************************************/
void SSW::InitGL() { PSSW psswChild = psswChildren;
// Configure the window for GL if pGLc non-NULL
if( pGLc && (! ConfigureForGL()) ) { // This is fatal for this window - if it is the main window,
// the ss will terminate
if( hwnd ) PostMessage( hwnd, WM_CLOSE, 0, 0l ); return; }
// If window configured for GL, hrc will have been set...
// Call the InitFunc
if( hrc && InitFunc ) { DWORD oldPriority;
// Bump up priority during initialization phase
oldPriority = GetPriorityClass( GetCurrentProcess() ); SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS );
SS_DBGLEVEL1( SS_LEVEL_INFO, "SSW::InitGL: Calling client GLInit for 0x%x\n", hwnd );
(*InitFunc)( DataPtr );
// restore original priority
SetPriorityClass( GetCurrentProcess(), oldPriority ); }
/* Send another Reshape, since initial one triggered by window
* creation would have been received before GL init'd */ Reshape();
// Next, init any child windows. This has to be done after the parent
// window initialization.
while( psswChild ) { if( psswChild->hwnd ) SendMessage( psswChild->hwnd, SS_WM_INITGL, 0, 0 ); else // Must be a logical sub-window
psswChild->InitGL(); psswChild = psswChild->psswSibling; } }
/**************************************************************************\
* ResizeStretch * * Resize the compatible bitmap for stretch blt mode * * There are 2 sizing modes. If bRatioMode, then we set the bitmap size * by dividing the window dimensions by the supplied ratios. In this case, * the base* values set a lower limit for the bitmap dimensions. Otherwise, the * base* values determine the bitmap dimensions. * * Feb. 12, 96 : [marcfo] * \**************************************************************************/
void SSW::ResizeStretch() { RECT rc; HBITMAP hbmNew; PVOID pvBits; int width, height; int cwidth, cheight; // client area size
SS_BITMAP *pssbm = &pStretch->ssbm;
cwidth = size.width; cheight = size.height;
if( pStretch->bRatioMode ) { width = (int) ( (float)cwidth / pStretch->widthRatio ); height = (int) ( (float)cheight / pStretch->heightRatio ); if( width < pStretch->baseWidth ) width = pStretch->baseWidth; if( height < pStretch->baseHeight ) height = pStretch->baseHeight ; } else { width = pStretch->baseWidth; height = pStretch->baseHeight; }
// Limit width, height to window dimensions
if( width > cwidth ) width = cwidth; if( height > cheight ) height = cheight;
// If same size, get out
if( (width == pssbm->size.width) && (height == pssbm->size.height) ) return;
pssbm->size.width = width; pssbm->size.height = height;
#if 1
// Use system palette
hbmNew = SSDIB_CreateCompatibleDIB(hdc, NULL, width, height, &pvBits); #else
// Use log palette
hbmNew = SSDIB_CreateCompatibleDIB(hdc, gpss->pssPal ? gpss->pssPal->hPal : NULL, width, height, &pvBits); #endif
if (hbmNew) { if (pssbm->hbm != (HBITMAP) 0) { SelectObject( pssbm->hdc, pssbm->hbmOld ); DeleteObject( pssbm->hbm ); }
pssbm->hbm = hbmNew; pssbm->hbmOld = (HBITMAP) SelectObject( pssbm->hdc, pssbm->hbm ); } }
/**************************************************************************\
* Resize * * Resize wrapper * * Called in response to WM_SIZE. * \**************************************************************************/
void SSW::Resize( int width, int height ) { size.width = width; size.height = height;
if( pStretch ) { // May have to resize associated bitmap
ResizeStretch(); }
if( psswChildren ) { // May need to resize any children
PSSW pssw = psswChildren; while( pssw ) { // Get new size/motion for the floater
pssw->GetChildInfo(); pssw->SetSSWindowPos(); if( !pssw->hwnd ) { // Handle sub-window case
// Need to call Reshape, since win32 system won't send WM_SIZE.
pssw->Reshape(); } pssw = pssw->psswSibling; } }
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 SSW::Repaint( BOOL bCheckUpdateRect ) { if( !hwnd ) return;
RECT rect, *pRect = NULL;
if( bCheckUpdateRect ) { GetUpdateRect( hwnd, &rect, FALSE ); // mf: Above supposed to return NULL if rect is all 0's,
// but this doesn't happen
if( NULL_UPDATE_RECT( &rect ) ) return; pRect = ▭ }
if( RepaintFunc ) (*RepaintFunc)( pRect, DataPtr ); }
/**************************************************************************\
* NeedStretchedWindow * * Check if stretch mode is necessary * \**************************************************************************/
BOOL SSW::NeedStretchedWindow() { if( (pStretch->baseWidth >= size.width) && (pStretch->baseHeight >= size.height) ) { return FALSE; } return TRUE; }
/**************************************************************************\
* SetSSWindowPos * * Set new size and position for an SSW * \**************************************************************************/
void SSW::SetSSWindowPos() { SetSSWindowPos( 0 ); }
void SSW::SetSSWindowPos( int flags ) { if( hwnd ) { SetWindowPos(hwnd, 0, pos.x, pos.y, size.width, size.height, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE | flags ); // Note: If flags does not specify SWP_NOREDRAW, this generates a WM_PAINT
// msg for the entire window region
} else if( psswParent && !pStretch ) { // Set viewport for new position
// (mf: if pStretch, shouldn't need to do anything, as viewport should
// have been already set to the bitmap)
int posy = GLPosY(); glViewport( pos.x, posy, size.width, size.height ); glScissor( pos.x, posy, size.width, size.height ); glAddSwapHintRect( pos.x, posy, size.width, size.height ); } }
/******************************Public*Routine******************************\
* SetAspectRatio * * Resize a child window to conform to the supplied aspect ratio. We do this by * maintaining the existing width, and adjusting the height. * * Window resize seems to be executed synchronously, so gl should be able to * immediately validate its buffer dimensions (we count on it). * * Returns TRUE if new height is different from last, else FALSE. \**************************************************************************/
BOOL SSW::SetAspectRatio( FLOAT fAspect ) { if( !psswParent ) return FALSE;
int oldHeight; UINT uFlags = 0;
// Check for zero fAspect
if( fAspect == 0.0f ) fAspect = 1.0f;
oldHeight = size.height; // Set the new height, based on desired aspect ratio
size.height = (int) ((FLOAT) size.width / fAspect); // make sure new height not TOO big!
ValidateChildSize();
if( size.height == oldHeight ) // no change
return FALSE;
// make sure current position still valid when height changes
if( !bValidateChildPos() ) { // current position OK, don't need to move it
uFlags |= SWP_NOMOVE; } SetSSWindowPos( uFlags );
// ! remember not to call the client's ReshapeFunc here, as SetAspectRatio
// may be called by the client in response to a window resize, resulting in
// an infinite loop
//mf: but if there is no size change (above) we return, avoiding the
// infinite loop
if( !hwnd ) // Need to call Reshape, since win32 system won't send WM_SIZE. Need
// to fix to avoid possible infinite loops
Reshape();
return TRUE; }
/**************************************************************************\
* CalcNextWindowPos * * Calculate the next position for a moving window, using the pMotion data. * If the new position would cause the window to bounce off the * edge of its parent, return TRUE. * \**************************************************************************/
BOOL SSW::CalcNextWindowPos() { POINT2D *fpos = &pMotion->pos; IPOINT2D *ipos = &pos; POINT2D *posInc = &pMotion->posInc; POINT2D *posIncV = &pMotion->posIncVary; POINT2D *posIncCur = &pMotion->posIncCur; BOOL bounce = FALSE;
if( !psswParent ) return FALSE;
// Compute the next window position.
fpos->x += posIncCur->x; fpos->y += posIncCur->y; ipos->x = (int) fpos->x; ipos->y = (int) fpos->y;
if ( (ipos->x + size.width) > psswParent->size.width) { // Right hit
ipos->x = psswParent->size.width - size.width; fpos->x = (float) ipos->x; posIncCur->x = - ss_fRand( posInc->x - posIncV->x, posInc->x + posIncV->x ); if( posIncCur->x > -0.5f ) posIncCur->x = -0.5f; bounce = TRUE; } else if (ipos->x < 0) { // Left hit
ipos->x = 0; fpos->x = 0.0f; posIncCur->x = ss_fRand( posInc->x - posIncV->x, posInc->x + posIncV->x ); if( posIncCur->x < 0.5f ) posIncCur->x = 0.5f; bounce = TRUE; }
if ( (ipos->y + size.height) > psswParent->size.height) { // Bottom hit
ipos->y = psswParent->size.height - size.height; fpos->y = (float) (ipos->y); posIncCur->y = - ss_fRand( posInc->y - posIncV->y, posInc->y + posIncV->y ); if( posIncCur->y > -0.5f ) posIncCur->y = -0.5f; bounce = TRUE; } else if (ipos->y < 0) { // Top hit
ipos->y = 0; fpos->y = 0.0f; posIncCur->y = ss_fRand( posInc->y - posIncV->y, posInc->y + posIncV->y ); if( posIncCur->y < 0.5f ) posIncCur->y = 0.5f; bounce = TRUE; } return bounce; }
/**************************************************************************\
* MoveSSWindow * * This is the function that moves the OpenGL window around, causing it to * bounce around. Each time the window is moved, the contents of the * window are updated from the hidden (or back) buffer by SwapBuffers(). * * The bRedrawBg flag determines whether the area that was covered by the old * position should be updated by the parent window. * \**************************************************************************/
void SSW::MoveSSWindow( BOOL bRedrawBg ) { BOOL bounce; int flags = SWP_NOSIZE;
// Synchronize with OpenGL. Flush OpenGL commands and wait for completion.
glFinish();
// Move the window
bounce = CalcNextWindowPos();
if( bounce && FloaterBounceFunc ) // The window bounced off one of the sides
// ! This function should *not* be used for rendering - for
// informational purposes only (.e.g. changing the spin of a
// rotating object).
(*FloaterBounceFunc)( DataPtr );
if( !bRedrawBg ) flags |= SWP_NOREDRAW; SetSSWindowPos( flags ); }
/**************************************************************************\
* UpdateWindow * * Update the window * * Ccurrently 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 SSW::UpdateWindow() { // update any children first
PSSW pssw = psswChildren; while( pssw ) { pssw->UpdateWindow(); pssw = pssw->psswSibling; }
//mf: semi-kluge
// If this window is a subWindow in a non-generic implementation, the
// background of the parent may be invalid (this may eventually be
// useful for regular windows, which is why we don't && !hwnd)
if( psswParent && psswParent->bValidateBg && pGLc && !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) ) { // Clear the entire parent window
// mf: I think this is only needed for double-buffered schemes, since
// the windowing system should repaint the front buffer in this case.
glDisable( GL_SCISSOR_TEST ); glClear( GL_COLOR_BUFFER_BIT ); glEnable( GL_SCISSOR_TEST ); psswParent->bValidateBg = FALSE; }
if( !UpdateFunc ) return;
// bDoubleBuf and pStretch should be mutually exclusive...
if( bDoubleBuf || pStretch ) { UpdateDoubleBufWin(); } else { //mf: ? where's the clearing here ? (true, no one uses this path...)
if( pMotion ) MoveSSWindow( TRUE ); (*UpdateFunc)( DataPtr ); } }
/**************************************************************************\
* UpdateDoubleBufWin * * This is used when moving a double buffered window around. It will * work for all configurations. * \**************************************************************************/
void SSW::UpdateDoubleBufWin() { if( !hwnd ) { UpdateDoubleBufSubWin(); return; }
RECT updateRect;
// Move the window
if( pMotion ) { // Save child update rect before move
GetSSWindowRect( &updateRect ); // Move window, without repainting exposed area
MoveSSWindow( FALSE ); }
// Update the back buffer
(*UpdateFunc)( DataPtr );
if( pMotion ) { // (pMotion will be NULL if this window has no parent)
if( hwnd ) { // Paint the exposed area with bg brush (the current image will
// be partially erased momentarily, until the SwapBuffers() call
// comes through)
// (This rect should be clipped to our new window position...)
DrawGdiRect( psswParent->hdc, gpss->hbrBg, &updateRect ); } else { //mf: currently this path not possible, since if !hwnd, we use one of the
// UpdateDoubleBufSubWin* functions
SS_WARNING( "SSW::UpdateDoubleBufWin: no hwnd\n" ); // sub-window case : need to do our own clipping
RECT newRect; GetSSWindowRect( &newRect ); DrawGdiDeltaRect( psswParent->hdc, gpss->hbrBg, &updateRect, &newRect ); } }
// Swap to the new window position
SwapSSBuffers(); }
/**************************************************************************\
* UpdateDoubleBufSubWin * * Used for generic double buffered gl sub-windows. * \**************************************************************************/
void SSW::UpdateDoubleBufSubWin() { GLRECT curRect, newRect;
// AddSwapHintRect for current position
glAddSwapHintRect( pos.x, GLPosY(), size.width, size.height );
if( pMotion ) {
// Save current rect
curRect.x = pos.x; curRect.y = GLPosY(); curRect.width = size.width; curRect.height = size.height;
// Move window, without repainting exposed area
MoveSSWindow( FALSE );
// Get new rect
newRect.x = pos.x; newRect.y = GLPosY(); newRect.width = size.width; newRect.height = size.height;
DrawGLDeltaRect( &curRect, &newRect );
// Have to consider previous rect for ICD or MCD
if( !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) ) { DrawGLDeltaRect( &lastRect, &newRect ); lastRect = curRect; }
// Reset scissor to new rect (this *was* set by MoveSSWindow, but
// DrawGLDeltaRect sets scissor to do its clearing
glScissor( newRect.x, newRect.y, newRect.width, newRect.height ); }
// Update the back buffer
(*UpdateFunc)( DataPtr );
// Swap to the new window position
SwapSSBuffers(); }
/******************************Public*Routine******************************\
* RandomWindowPos * * Sets a new random window position and motion * \**************************************************************************/
void SSW::RandomWindowPos() { if( psswParent ) { if( !hwnd ) { // sub-window : manually clear old window rect
if( bDoubleBuf ) { glClear( GL_COLOR_BUFFER_BIT ); } else { RECT oldRect; GetSSWindowRect( &oldRect ); DrawGdiRect( psswParent->hdc, gpss->hbrBg, &oldRect ); } }
// Calc and set new position
pos.x = ss_iRand2( 0, (psswParent->size.width - size.width) ); pos.y = ss_iRand2( 0, (psswParent->size.height - size.height) ); SetSSWindowPos( SWP_NOSIZE );
// Reset motion
if( pMotion ) ResetMotion(); } }
/**************************************************************************\
* ResetMotion * * Calculate a random position and motion vector for the floater window * Note that a floating point position is maintained for DDA window movement * \**************************************************************************/
void SSW::ResetMotion() { if( !psswParent || !pMotion ) // Only child windows can be reset
return;
// Set floating point pos also, for DDA
pMotion->pos.x = (float) pos.x; pMotion->pos.y = (float) pos.y;
// also reset the window motion directions
if( ss_iRand(2) ) // 0 or 1
pMotion->posIncCur.x = - pMotion->posIncCur.x; if( ss_iRand(2) ) pMotion->posIncCur.y = - pMotion->posIncCur.y; }
/**************************************************************************\
* ValidateChildSize * * Make sure it's not bigger than its parent * \**************************************************************************/
void SSW::ValidateChildSize() { if( !psswParent ) return;
SS_CLAMP_TO_RANGE2( size.width, 0, psswParent->size.width ); SS_CLAMP_TO_RANGE2( size.height, 0, psswParent->size.height ); }
/**************************************************************************\
* bValidateChildPos * * Make sure that with the current window position, none of the floating * window extends beyond the parent window. * \**************************************************************************/
BOOL SSW::bValidateChildPos() { BOOL bRet = FALSE;
if( !psswParent ) return FALSE;
if ( (pos.x + size.width) > psswParent->size.width) { pos.x = psswParent->size.width - size.width; bRet = TRUE; }
if ( (pos.y + size.height) > psswParent->size.height) { pos.y = psswParent->size.height - size.height; bRet = TRUE; } return bRet; }
/**************************************************************************\
* GetSSWindowRect * * Return window position and size in supplied RECT structure * * mf: this rect is relative to the parent \**************************************************************************/
void SSW::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 SSW::GLPosY() { if( !psswParent ) return 0;
return psswParent->size.height - size.height - pos.y; }
/**************************************************************************\
* SwapStretchBuffers * * Swaps from the stretch buffer to the GL window, using StretchBlt * \**************************************************************************/
void SSW::SwapStretchBuffers() { SS_BITMAP *pssbm = &pStretch->ssbm;
if( (size.width == pssbm->size.width) && (size.height == pssbm->size.height) ) // buffers same size
{ BitBlt(hdc, 0, 0, size.width, size.height, pssbm->hdc, 0, 0, SRCCOPY); } else { StretchBlt(hdc, 0, 0, size.width, size.height, pssbm->hdc, 0, 0, pssbm->size.width, pssbm->size.height, SRCCOPY); } GdiFlush(); }
/**************************************************************************\
* SwapBuffers * * Wrapper for SwapBuffers / SwapStretchBuffers * \**************************************************************************/
void SSW::SwapSSBuffers() { if( pStretch ) SwapStretchBuffers(); else if( bDoubleBuf ) { SwapBuffers( hdc ); } }
/**************************************************************************\
* 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 SSW::Reshape() { // Point to size of window, or bitmap if it has one
ISIZE *pSize = &size; if( pStretch ) pSize = &pStretch->ssbm.size;
// If the window has an hrc, set default viewport
if( hrc ) { if( hwnd ) glViewport( 0, 0, pSize->width, pSize->height ); else if ( psswParent ) { // sub-window (only 1 level of sub-windowing supported)
//mf: klugey ? - should take into account non-GL and single buffer...
#if 1
// clear entire window to black
glDisable( GL_SCISSOR_TEST ); glClear( GL_COLOR_BUFFER_BIT ); glEnable( GL_SCISSOR_TEST ); #endif
// Convert win32 y-coord to GL
glViewport( pos.x, GLPosY(), pSize->width, pSize->height ); } }
if( ReshapeFunc ) { (*ReshapeFunc)( pSize->width, pSize->height, DataPtr ); } }
/******************************Public*Routine******************************\
* GdiClear * * Clears window using Gdi FillRect \**************************************************************************/
void SSW::GdiClear() { if( !hdc ) return;
RECT rect;
//mf: this should use GetClientRect
GetSSWindowRect( &rect );
FillRect( hdc, &rect, gpss->hbrBg ); GdiFlush(); }
/******************************Public*Routine******************************\
* MyAddSwapHintRect * \**************************************************************************/
static void _stdcall MyAddSwapHintRect(GLint xs, GLint ys, GLint xe, GLint ye) { return; }
/******************************Public*Routine******************************\
* QueryAddSwapHintRectWIN * \**************************************************************************/
static void ss_QueryAddSwapHintRect() { glAddSwapHintRect = (PFNGLADDSWAPHINTRECTWINPROC) wglGetProcAddress("glAddSwapHintRectWIN"); if (glAddSwapHintRect == NULL) { glAddSwapHintRect = MyAddSwapHintRect; } }
/******************************Public*Routine******************************\
* DrawGdiDeltaRect * * Draw the exposed area by transition from rect1 to rect2 \**************************************************************************/
static void DrawGdiDeltaRect( HDC hdc, HBRUSH hbr, RECT *pRect1, RECT *pRect2 ) { if( (pRect1 == NULL) || (pRect2 == NULL) ) { SS_WARNING( "DrawGdiDeltaRect : one or both rects are NULL\n" ); return; }
// Draw 2 rects
RECT rect;
// Rect exposed in x-direction:
rect.top = pRect1->top; rect.bottom = pRect1->bottom; if( pRect2->left > pRect1->left ) { // moving right
rect.left = pRect1->left; rect.right = pRect2->left; } else { // moving left
rect.left = pRect2->right; rect.right = pRect1->right; } FillRect( hdc, &rect, hbr );
// Rect exposed in y-direction:
rect.left = pRect1->left; rect.right = pRect1->right; if( pRect2->bottom > pRect1->bottom ) { // moving down
rect.top = pRect1->top; rect.bottom = pRect2->top; } else { // moving up
rect.top = pRect2->bottom; rect.bottom = pRect1->bottom; } FillRect( hdc, &rect, hbr );
GdiFlush(); }
/******************************Public*Routine******************************\
* DrawGLDeltaRect * * Draw the exposed area by transition from rect1 to rect2 \**************************************************************************/
static void DrawGLDeltaRect( GLRECT *pRect1, GLRECT *pRect2 ) { if( (pRect1 == NULL) || (pRect2 == NULL) ) { SS_WARNING( "DrawGLDeltaRect : one or both rects are NULL\n" ); return; }
// Draw 2 rects :
//mf: !!! this assumes rect1 and rect2 have same dimensions !
GLRECT rect;
// Rect exposed in x-direction:
rect.height = pRect1->height; rect.y = pRect1->y;
if( pRect2->x > pRect1->x ) { // moving right
rect.width = pRect2->x - pRect1->x; rect.x = pRect1->x; } else { // moving left
rect.width = pRect1->x - pRect2->x; rect.x = pRect2->x + pRect2->width; }
glScissor( rect.x, rect.y, rect.width, rect.height ); glClear( GL_COLOR_BUFFER_BIT );
// Rect exposed in y-direction:
rect.width = pRect1->width; rect.x = pRect1->x;
if( pRect2->y > pRect1->y ) { // moving up
rect.height = pRect2->y - pRect1->y; rect.y = pRect1->y; } else { // moving down
rect.height = pRect1->y - pRect2->y; rect.y = pRect2->y + pRect2->height; }
glScissor( rect.x, rect.y, rect.width, rect.height ); glClear( GL_COLOR_BUFFER_BIT ); }
|