1630 lines
45 KiB
C++
1630 lines
45 KiB
C++
/******************************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 );
|
|
}
|
|
|