Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1625 lines
45 KiB

4 years ago
  1. /******************************Module*Header*******************************\
  2. * Module Name: sswindow.cxx
  3. *
  4. * Copyright (c) 1996 Microsoft Corporation
  5. *
  6. \**************************************************************************/
  7. #include <windows.h>
  8. #include <windowsx.h>
  9. #include "scrnsave.h"
  10. #include "glscrnsv.h"
  11. #include "ssintrnl.hxx"
  12. #include "sswindow.hxx"
  13. #include "ssutil.hxx"
  14. static void (__stdcall *glAddSwapHintRect)(GLint, GLint, GLint, GLint);
  15. // externs from ssinit.cxx
  16. extern void *gDataPtr;
  17. extern void (*gReshapeFunc)(int, int, void *);
  18. extern void (*gRepaintFunc)( LPRECT, void *);
  19. extern void (*gUpdateFunc)( void *);
  20. extern void (*gInitFunc)( void *);
  21. extern void (*gFinishFunc)( void *);
  22. extern void (*gFloaterBounceFunc)( void *);
  23. // forwards
  24. static void GetWindowSize( HWND hwnd, ISIZE *pSize );
  25. static void ss_QueryAddSwapHintRect();
  26. static void DrawGdiDeltaRect( HDC hdc, HBRUSH hbr, RECT *pRect1, RECT *pRect2 );
  27. static void DrawGLDeltaRect( GLRECT *pRect1, GLRECT *pRect2 );
  28. /**************************************************************************\
  29. * SSW constructor
  30. *
  31. \**************************************************************************/
  32. SSW::SSW( PSSW psswParentArg, ISIZE *pSize, IPOINT2D *pPos, BOOL bMotion,
  33. SSCHILDSIZEPROC ChildSizeFuncArg )
  34. {
  35. // Basic initialization
  36. Reset();
  37. // Initialization based on constructor parameters
  38. psswParent = psswParentArg;
  39. ChildSizeFunc = ChildSizeFuncArg;
  40. if( pSize )
  41. size = *pSize;
  42. if( pPos )
  43. pos = *pPos;
  44. else
  45. pos.x = pos.y = 0;
  46. if( bMotion && psswParent ) {
  47. // Allocate motion structure
  48. pMotion = (MOTION *)
  49. LocalAlloc( LMEM_ZEROINIT | LMEM_FIXED, sizeof(MOTION) );
  50. // If pMotion is NULL, then motion is disabled
  51. }
  52. // Call back to the client screen saver to determine size and motion
  53. // characteristics of child based on its parent size.
  54. GetChildInfo(); // this can set pos and size
  55. if( pMotion ) {
  56. if( pPos == NULL ) {
  57. // Set a random window pos
  58. pos.x = ss_iRand2( 0, (psswParent->size.width - size.width) );
  59. pos.y = ss_iRand2( 0, (psswParent->size.height - size.height) );
  60. // Set the motion parameters
  61. ResetMotion();
  62. }
  63. // Have to make sure parent has an hdc so it can draw background when
  64. // this child moves
  65. if( !psswParent->hdc )
  66. psswParent->hdc = GetDC( psswParent->hwnd );
  67. }
  68. if( psswParent ) {
  69. // Need to add this pssw to its parent's list
  70. psswParent->AddChild( this );
  71. // Default is to be subWindow of parent
  72. psswParent->iSubWindow++; // increment reference count
  73. }
  74. }
  75. /**************************************************************************\
  76. * SSW constructor
  77. *
  78. * Used when wrapping an SSW around an already existing window
  79. * (as when drawing GL on dialog buttons)
  80. \**************************************************************************/
  81. SSW::SSW( PSSW psswParentArg, HWND hwndArg )
  82. {
  83. Reset();
  84. psswParent = psswParentArg;
  85. if( psswParent )
  86. // Need to add this pssw to its parent's list
  87. psswParent->AddChild( this );
  88. hwnd = hwndArg;
  89. if( !hwnd ) {
  90. SS_ERROR( "SSW::SSW : NULL hwnd\n" );
  91. return;
  92. }
  93. bOwnWindow = FALSE;
  94. // Get the window size
  95. GetWindowSize( hwnd, &size );
  96. gpss->sswTable.Register( hwnd, this );
  97. }
  98. /**************************************************************************\
  99. * Reset
  100. *
  101. * Reset parameters to default init state
  102. \**************************************************************************/
  103. void
  104. SSW::Reset()
  105. {
  106. // Basic initialization
  107. bOwnWindow = TRUE;
  108. iSubWindow = 0;
  109. bValidateBg = FALSE;
  110. wFlags = 0;
  111. hwnd = 0;
  112. hdc = 0;
  113. hrc = 0;
  114. pos.x = pos.y = 0;
  115. size.width = size.height = 0;
  116. psswParent = NULL;
  117. psswSibling = NULL;
  118. psswChildren = NULL;
  119. bDoubleBuf = FALSE;
  120. pStretch = NULL;
  121. pMotion = NULL;
  122. pGLc = NULL;
  123. InitFunc = NULL;
  124. UpdateFunc = NULL;
  125. ReshapeFunc = NULL;
  126. RepaintFunc = NULL;
  127. FloaterBounceFunc = NULL;
  128. FinishFunc = NULL;
  129. ChildSizeFunc = NULL;
  130. DataPtr = NULL;
  131. }
  132. /**************************************************************************\
  133. * SSW destructor
  134. *
  135. * This can be called when a window is closed, or by the ss client
  136. *
  137. \**************************************************************************/
  138. SSW::~SSW()
  139. {
  140. // If this window has any children, they will have to be terminated too
  141. if( psswChildren ) {
  142. PSSW psswChild = psswChildren;
  143. while( psswChild ) {
  144. // Delete first child in list
  145. if( psswChild->hwnd && bOwnWindow ) {
  146. // We created this window, we must destroy it
  147. DestroyWindow( psswChild->hwnd );
  148. } else {
  149. delete psswChild;
  150. }
  151. // Next child is now first child in list
  152. psswChild = psswChildren;
  153. }
  154. }
  155. if( psswParent )
  156. // Need to remove this pssw from its parent's list
  157. psswParent->RemoveChild( this );
  158. if( hwnd ) {
  159. // Remove from SSWTable
  160. gpss->sswTable.Remove( hwnd );
  161. } else {
  162. // subWindow
  163. if( psswParent ) {
  164. SS_ASSERT1( (psswParent->iSubWindow > 0),
  165. "Invalid subWindow reference count for pssw=0x%x\n", this );
  166. psswParent->iSubWindow--; // decrement subWindow reference count
  167. }
  168. }
  169. // Clean up GL
  170. if( hrc ) {
  171. // FinishFunc still needs gl
  172. if( FinishFunc )
  173. (*FinishFunc)( DataPtr );
  174. wglMakeCurrent( NULL, NULL );
  175. if( ! (wFlags & SS_HRC_PROXY_BIT) )
  176. wglDeleteContext( hrc );
  177. }
  178. // Clean up any bitmaps
  179. if( pStretch ) {
  180. SS_BITMAP *pssbm = &pStretch->ssbm;
  181. DeleteObject(SelectObject(pssbm->hdc, pssbm->hbmOld));
  182. DeleteDC(pssbm->hdc);
  183. }
  184. // Release the dc
  185. if( hdc ) {
  186. HWND hwndForHdc = hwnd ? hwnd : psswParent ? psswParent->hwnd : NULL;
  187. ReleaseDC(hwndForHdc, hdc);
  188. }
  189. }
  190. /**************************************************************************\
  191. * AddChild
  192. *
  193. * Add the supplied child SSW to this SSW.
  194. \**************************************************************************/
  195. void
  196. SSW::AddChild( PSSW psswChild )
  197. {
  198. if( !psswChildren ) {
  199. psswChildren = psswChild;
  200. return;
  201. }
  202. // Else travel along the sibling chain of psswChildren and deposit
  203. // psswChild at the end
  204. PSSW pssw = psswChildren;
  205. while( pssw->psswSibling )
  206. pssw = pssw->psswSibling;
  207. pssw->psswSibling = psswChild;
  208. }
  209. /**************************************************************************\
  210. * RemoveChild
  211. *
  212. * Remove this child from the parent's list
  213. *
  214. * Whoever calls this needs to update SSW_TABLE too...
  215. \**************************************************************************/
  216. BOOL
  217. SSW::RemoveChild( PSSW psswChild )
  218. {
  219. if( !psswChildren ) {
  220. // Something wrong - this window has no children
  221. SS_ERROR( "SSW::RemoveChild : no children\n" );
  222. return FALSE;
  223. }
  224. PSSW psswPrev;
  225. PSSW pssw = psswChildren;
  226. while( pssw != NULL ) {
  227. if( pssw == psswChild ) {
  228. // found it !
  229. if( psswChild == psswChildren )
  230. // The child being removed is the first in the list
  231. psswChildren = psswChild->psswSibling;
  232. else
  233. psswPrev->psswSibling = pssw->psswSibling;
  234. return TRUE;
  235. }
  236. // Move up the pointers
  237. psswPrev = pssw;
  238. pssw = psswPrev->psswSibling;
  239. }
  240. SS_ERROR( "SSW::RemoveChild : child not found\n" );
  241. return FALSE;
  242. }
  243. /**************************************************************************\
  244. * GetWindowSize
  245. *
  246. \**************************************************************************/
  247. static void
  248. GetWindowSize( HWND hwnd, ISIZE *pSize )
  249. {
  250. RECT clientRect;
  251. GetClientRect( hwnd, &clientRect );
  252. pSize->width = clientRect.right - clientRect.left + 1;
  253. pSize->height = clientRect.bottom - clientRect.top + 1;
  254. }
  255. /**************************************************************************\
  256. * CreateSSWindow
  257. *
  258. * Create OpenGL floater window. This window floats on top of the screen
  259. * saver window, bouncing off each of the screen edges.
  260. *
  261. * History
  262. * Apr. 28, 95 : [marcfo]
  263. * - Floater motion characteristics now defined by caller
  264. * Aug. 14, 95 : [marcfo]
  265. * - Position the window offscreen initially, to workaround a win95 bug
  266. * with a corrupted initial clip rect.
  267. *
  268. \**************************************************************************/
  269. BOOL
  270. SSW::CreateSSWindow(HINSTANCE hMainInstance, UINT uStyle, UINT uExStyle ,
  271. LPCTSTR pszWindowTitle, WNDPROC wndProcArg, LPCTSTR pszClassName, HWND hwndParentOverride )
  272. {
  273. IPOINT2D startPos;
  274. HWND hwndParent;
  275. if( hwndParentOverride )
  276. hwndParent = hwndParentOverride;
  277. else
  278. hwndParent = psswParent ? psswParent->hwnd : NULL;
  279. wndProc = wndProcArg;
  280. if( !pMotion )
  281. startPos = pos;
  282. else {
  283. // Initialize start position off screen to work around win95 screen
  284. // validation bug
  285. startPos.x = pos.x - psswParent->size.width;
  286. startPos.y = pos.y - psswParent->size.height;
  287. }
  288. hwnd = CreateWindowEx(
  289. uExStyle,
  290. pszClassName,
  291. pszWindowTitle,
  292. uStyle,
  293. startPos.x,
  294. startPos.y,
  295. size.width, // width
  296. size.height, // height
  297. hwndParent,
  298. NULL, // menu
  299. hMainInstance,
  300. (LPVOID) this
  301. );
  302. if (!hwnd) {
  303. //mf: could still continue here by using sub-windows
  304. SS_WARNING( "SSW::CreateSSWindow : CreateWindowEx failure\n" );
  305. return FALSE;
  306. }
  307. // This window is on its own now
  308. if( psswParent ) {
  309. SS_ASSERT1( (psswParent->iSubWindow > 0),
  310. "Invalid subWindow reference count for pssw=0x%x\n", this );
  311. psswParent->iSubWindow--; // decrement subWindow reference count
  312. }
  313. ShowWindow(hwnd, SW_SHOW);
  314. return TRUE;
  315. }
  316. /**************************************************************************\
  317. * GetChildInfo
  318. *
  319. * Call the window's ChildSizeFunc
  320. \**************************************************************************/
  321. void
  322. SSW::GetChildInfo( )
  323. {
  324. if( !ChildSizeFunc )
  325. return;
  326. CHILD_INFO childInfo;
  327. // Call the client's SizeFunc to get required info
  328. (*ChildSizeFunc)( &psswParent->size, &childInfo );
  329. // Pull required values into pssw and validate them
  330. size = childInfo.size;
  331. ValidateChildSize();
  332. if( !pMotion ) {
  333. pos = childInfo.pos;
  334. bValidateChildPos();
  335. } else {
  336. pMotion->posInc = childInfo.motionInfo.posInc;
  337. pMotion->posIncVary = childInfo.motionInfo.posIncVary;
  338. pMotion->posIncCur = pMotion->posInc;
  339. }
  340. }
  341. /**************************************************************************\
  342. * ConfigureForGdi
  343. *
  344. * Creates an hdc for the window
  345. *
  346. \**************************************************************************/
  347. BOOL
  348. SSW::ConfigureForGdi()
  349. {
  350. if( hdc )
  351. // already configured
  352. return TRUE;
  353. // Figure window to get hdc from
  354. HWND hwndForHdc = hwnd ? hwnd : psswParent ? psswParent->hwnd : NULL;
  355. if( !hwndForHdc || !(hdc = GetDC(hwndForHdc)) ) {
  356. SS_WARNING( "SSW::ConfigureForGdi failed\n" );
  357. return FALSE;
  358. }
  359. return TRUE;
  360. }
  361. /**************************************************************************\
  362. * ConfigureForGL
  363. *
  364. * Creates a GL rendering context for the specified window
  365. *
  366. \**************************************************************************/
  367. BOOL
  368. SSW::ConfigureForGL( SS_GL_CONFIG *pGLcArg )
  369. {
  370. pGLc = pGLcArg;
  371. return ConfigureForGL();
  372. }
  373. BOOL
  374. SSW::ConfigureForGL()
  375. {
  376. if( hrc )
  377. // Already configured...
  378. return TRUE;
  379. if( ConfigureForGdi() &&
  380. (hrc = hrcSetupGL()) )
  381. return TRUE;
  382. SS_WARNING( "SSW::ConfigureForGL failed\n" );
  383. return FALSE;
  384. }
  385. /**************************************************************************\
  386. * hrcSetupGL
  387. *
  388. * Setup OpenGL.
  389. *
  390. \**************************************************************************/
  391. #define NULL_RC ((HGLRC) 0)
  392. HGLRC
  393. SSW::hrcSetupGL()
  394. {
  395. if( !pGLc )
  396. return NULL_RC;
  397. //mf: This routine does not yet fully support logical sub-windows...
  398. HGLRC hrc;
  399. HDC hgldc;
  400. int pfFlags = pGLc->pfFlags;
  401. PIXELFORMATDESCRIPTOR pfd = {0};
  402. pStretch = pGLc->pStretch;
  403. if( pStretch ) {
  404. if( NeedStretchedWindow() ) {
  405. // Only need single buffered pixel format
  406. pfFlags &= ~SS_DOUBLEBUF_BIT;
  407. pfFlags |= SS_BITMAP_BIT; // yup, BOTH window and bitmap need this
  408. } else
  409. // Turn off stretching
  410. pStretch = NULL;
  411. }
  412. // If preview mode or config mode, don't allow pixel formats that need
  413. // the system palette, as this will create much ugliness.
  414. if( ss_fPreviewMode() || ss_fConfigMode() )
  415. pfFlags |= SS_NO_SYSTEM_PALETTE_BIT;
  416. // If config mode, force a non-accelerated pixel format, as WNDOBJ's
  417. // seem to have problems with MCD, ICD
  418. if( ss_fConfigMode() )
  419. pfFlags |= SS_GENERIC_UNACCELERATED_BIT;
  420. bDoubleBuf = SS_HAS_DOUBLEBUF( pfFlags );
  421. if( !SSU_SetupPixelFormat( hdc, pfFlags, &pfd ) )
  422. return NULL_RC;
  423. // Update pGLc->pfFlags based on pfd returned
  424. // !!! mf: klugey, fix after SUR
  425. // (for now, the only ones we care about are the generic/accelerated flags)
  426. if( (pfd.dwFlags & (PFD_GENERIC_FORMAT|PFD_GENERIC_ACCELERATED))
  427. == PFD_GENERIC_FORMAT )
  428. pGLc->pfFlags |= SS_GENERIC_UNACCELERATED_BIT;
  429. if( SSU_bNeedPalette( &pfd ) ) {
  430. // Note: even if bStretch, need to set up palette here so they match
  431. if( !gpss->pssPal ) {
  432. SS_PAL *pssPal;
  433. BOOL bTakeOverPalette = ss_fFullScreenMode() ? TRUE : FALSE;
  434. // The global palette has not been created yet - do it
  435. // SS_PAL creation requires pixel format descriptor for color bit
  436. // information, etc. (the pfd is cached in SS_PAL, since for
  437. // palette purposes it is the same for all windows)
  438. pssPal = new SS_PAL( hdc, &pfd, bTakeOverPalette );
  439. if( !pssPal )
  440. return NULL_RC;
  441. // Set approppriate palette manage proc
  442. if( ss_fFullScreenMode() )
  443. pssPal->paletteManageProc = FullScreenPaletteManageProc;
  444. else
  445. // use regular palette manager proc
  446. pssPal->paletteManageProc = PaletteManageProc;
  447. gpss->pssPal = pssPal;
  448. }
  449. // Realize the global palette in this window
  450. //mf: assume we're realizing in foreground
  451. HWND hwndPal = hwnd ? hwnd : psswParent ? psswParent->hwnd : NULL;
  452. if( hwndPal )
  453. gpss->pssPal->Realize( hwndPal, hdc, FALSE );
  454. }
  455. if( pStretch ) {
  456. // Stretch blt mode: For every frame, we'll be doing a StretchBlt
  457. // from a DIB to the screen. Need to set up a compatible memdc.
  458. SS_BITMAP *pssbm;
  459. pssbm = &pStretch->ssbm;
  460. pssbm->hdc = CreateCompatibleDC(hdc);
  461. if( !pssbm->hdc )
  462. return NULL_RC;
  463. ResizeStretch(); // this creates the DIB Section
  464. pfFlags = 0;
  465. pfFlags |= SS_BITMAP_BIT;
  466. if( !SSU_SetupPixelFormat( pssbm->hdc, pfFlags, &pfd ) ) {
  467. return NULL_RC;
  468. }
  469. //mf: this ppfd's palette bits must match the window's !!
  470. // If window needs palette, so does bitmap...
  471. if( gpss->pssPal ) {
  472. SS_PAL *pssPal = gpss->pssPal;
  473. extern void ssw_UpdateDIBColorTable( HDC, HDC );
  474. ssw_UpdateDIBColorTable( pssbm->hdc, hdc );
  475. }
  476. hgldc = pssbm->hdc;
  477. } else {
  478. hgldc = hdc;
  479. }
  480. if( pGLc->hrc ) {
  481. // Use the supplied hrc
  482. hrc = pGLc->hrc;
  483. // Set flag so we don't delete this borrowed hrc when the SSW terminates
  484. wFlags |= SS_HRC_PROXY_BIT;
  485. } else
  486. // Create a new hrc
  487. hrc = wglCreateContext(hgldc);
  488. if( !hrc || !wglMakeCurrent(hgldc, hrc) ) {
  489. SS_WARNING( "SSW::hrcSetupGL : hrc context failure\n" );
  490. return NULL_RC;
  491. }
  492. if( !hwnd && (bDoubleBuf || pStretch) ) {
  493. // enable scissoring
  494. glEnable( GL_SCISSOR_TEST );
  495. if( !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) ) {
  496. // MCD or ICD, possible hardware implementation - we maintain
  497. // a lastRect to handle SwapBuffer issues
  498. lastRect.x = lastRect.y = lastRect.width = lastRect.height = 0;
  499. }
  500. }
  501. SS_DBGLEVEL2( SS_LEVEL_INFO,
  502. "SSW::hrcSetupGL: wglMakeCurrent( hrc=0x%x, hwnd=0x%x )\n", hrc, hwnd );
  503. //mf: Note that these queries are based on a single gl window screen saver. In
  504. // a more complicated scenario, these capabilities could be queried on a
  505. // per-window basis (since support could vary with pixel formats).
  506. // Query the GL version - sets support for any new (e.g. 1.1) functionality
  507. ss_QueryGLVersion();
  508. // Query paletted texture extension
  509. ss_QueryPalettedTextureEXT();
  510. // Query the AddSwapHintRect WIN extension
  511. ss_QueryAddSwapHintRect();
  512. // Pull in any Func's that were already defined (for compatibility with
  513. // old mechanism)
  514. InitFunc = gInitFunc;
  515. UpdateFunc = gUpdateFunc;
  516. ReshapeFunc = gReshapeFunc;
  517. RepaintFunc = gRepaintFunc;
  518. FloaterBounceFunc = gFloaterBounceFunc;
  519. FinishFunc = gFinishFunc;
  520. DataPtr = gDataPtr;
  521. return hrc;
  522. }
  523. /**************************************************************************\
  524. * MakeCurrent
  525. *
  526. * Call wglMakeCurrent for this window's hrc. Note: an ss client may have
  527. * more than one hrc (e.g. pipes), in which case it is the client's
  528. * responsibility to make current.
  529. \**************************************************************************/
  530. void
  531. SSW::MakeCurrent()
  532. {
  533. if( ! wglMakeCurrent( hdc, hrc ) )
  534. SS_WARNING( "SSW::MakeCurrent : wglMakeCurrent failure\n" );
  535. }
  536. /**************************************************************************\
  537. * InitGL
  538. *
  539. * Call the window's GL Init Func
  540. *
  541. * Priority is raised to expedite any initialization (e.g. loading and
  542. * processing textures can take a while.
  543. *
  544. * A Reshape msg is sent to the client ss, as this is required for setting
  545. * glViewport, etc.
  546. \**************************************************************************/
  547. void
  548. SSW::InitGL()
  549. {
  550. PSSW psswChild = psswChildren;
  551. // Configure the window for GL if pGLc non-NULL
  552. if( pGLc && (! ConfigureForGL()) ) {
  553. // This is fatal for this window - if it is the main window,
  554. // the ss will terminate
  555. if( hwnd )
  556. PostMessage( hwnd, WM_CLOSE, 0, 0l );
  557. return;
  558. }
  559. // If window configured for GL, hrc will have been set...
  560. // Call the InitFunc
  561. if( hrc && InitFunc ) {
  562. DWORD oldPriority;
  563. // Bump up priority during initialization phase
  564. oldPriority = GetPriorityClass( GetCurrentProcess() );
  565. SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS );
  566. SS_DBGLEVEL1( SS_LEVEL_INFO,
  567. "SSW::InitGL: Calling client GLInit for 0x%x\n", hwnd );
  568. (*InitFunc)( DataPtr );
  569. // restore original priority
  570. SetPriorityClass( GetCurrentProcess(), oldPriority );
  571. }
  572. /* Send another Reshape, since initial one triggered by window
  573. * creation would have been received before GL init'd
  574. */
  575. Reshape();
  576. // Next, init any child windows. This has to be done after the parent
  577. // window initialization.
  578. while( psswChild ) {
  579. if( psswChild->hwnd )
  580. SendMessage( psswChild->hwnd, SS_WM_INITGL, 0, 0 );
  581. else
  582. // Must be a logical sub-window
  583. psswChild->InitGL();
  584. psswChild = psswChild->psswSibling;
  585. }
  586. }
  587. /**************************************************************************\
  588. * ResizeStretch
  589. *
  590. * Resize the compatible bitmap for stretch blt mode
  591. *
  592. * There are 2 sizing modes. If bRatioMode, then we set the bitmap size
  593. * by dividing the window dimensions by the supplied ratios. In this case,
  594. * the base* values set a lower limit for the bitmap dimensions. Otherwise, the
  595. * base* values determine the bitmap dimensions.
  596. *
  597. * Feb. 12, 96 : [marcfo]
  598. *
  599. \**************************************************************************/
  600. void
  601. SSW::ResizeStretch()
  602. {
  603. RECT rc;
  604. HBITMAP hbmNew;
  605. PVOID pvBits;
  606. int width, height;
  607. int cwidth, cheight; // client area size
  608. SS_BITMAP *pssbm = &pStretch->ssbm;
  609. cwidth = size.width;
  610. cheight = size.height;
  611. if( pStretch->bRatioMode ) {
  612. width = (int) ( (float)cwidth / pStretch->widthRatio );
  613. height = (int) ( (float)cheight / pStretch->heightRatio );
  614. if( width < pStretch->baseWidth )
  615. width = pStretch->baseWidth;
  616. if( height < pStretch->baseHeight )
  617. height = pStretch->baseHeight ;
  618. } else {
  619. width = pStretch->baseWidth;
  620. height = pStretch->baseHeight;
  621. }
  622. // Limit width, height to window dimensions
  623. if( width > cwidth )
  624. width = cwidth;
  625. if( height > cheight )
  626. height = cheight;
  627. // If same size, get out
  628. if( (width == pssbm->size.width) && (height == pssbm->size.height) )
  629. return;
  630. pssbm->size.width = width;
  631. pssbm->size.height = height;
  632. #if 1
  633. // Use system palette
  634. hbmNew = SSDIB_CreateCompatibleDIB(hdc, NULL, width, height, &pvBits);
  635. #else
  636. // Use log palette
  637. hbmNew = SSDIB_CreateCompatibleDIB(hdc,
  638. gpss->pssPal ? gpss->pssPal->hPal : NULL,
  639. width, height, &pvBits);
  640. #endif
  641. if (hbmNew)
  642. {
  643. if (pssbm->hbm != (HBITMAP) 0)
  644. {
  645. SelectObject( pssbm->hdc, pssbm->hbmOld );
  646. DeleteObject( pssbm->hbm );
  647. }
  648. pssbm->hbm = hbmNew;
  649. pssbm->hbmOld = (HBITMAP) SelectObject( pssbm->hdc, pssbm->hbm );
  650. }
  651. }
  652. /**************************************************************************\
  653. * Resize
  654. *
  655. * Resize wrapper
  656. *
  657. * Called in response to WM_SIZE.
  658. *
  659. \**************************************************************************/
  660. void
  661. SSW::Resize( int width, int height )
  662. {
  663. size.width = width;
  664. size.height = height;
  665. if( pStretch ) {
  666. // May have to resize associated bitmap
  667. ResizeStretch();
  668. }
  669. if( psswChildren ) {
  670. // May need to resize any children
  671. PSSW pssw = psswChildren;
  672. while( pssw ) {
  673. // Get new size/motion for the floater
  674. pssw->GetChildInfo();
  675. pssw->SetSSWindowPos();
  676. if( !pssw->hwnd ) {
  677. // Handle sub-window case
  678. // Need to call Reshape, since win32 system won't send WM_SIZE.
  679. pssw->Reshape();
  680. }
  681. pssw = pssw->psswSibling;
  682. }
  683. }
  684. Reshape();
  685. }
  686. /**************************************************************************\
  687. * Repaint
  688. *
  689. * Repaint wrapper
  690. *
  691. * Called in response to WM_PAINT.
  692. *
  693. \**************************************************************************/
  694. #define NULL_UPDATE_RECT( pRect ) \
  695. ( ((pRect)->left == 0) && \
  696. ((pRect)->right == 0) && \
  697. ((pRect)->top == 0) && \
  698. ((pRect)->bottom == 0) )
  699. void
  700. SSW::Repaint( BOOL bCheckUpdateRect )
  701. {
  702. if( !hwnd )
  703. return;
  704. RECT rect, *pRect = NULL;
  705. if( bCheckUpdateRect ) {
  706. GetUpdateRect( hwnd, &rect, FALSE );
  707. // mf: Above supposed to return NULL if rect is all 0's,
  708. // but this doesn't happen
  709. if( NULL_UPDATE_RECT( &rect ) )
  710. return;
  711. pRect = &rect;
  712. }
  713. if( RepaintFunc )
  714. (*RepaintFunc)( pRect, DataPtr );
  715. }
  716. /**************************************************************************\
  717. * NeedStretchedWindow
  718. *
  719. * Check if stretch mode is necessary
  720. *
  721. \**************************************************************************/
  722. BOOL
  723. SSW::NeedStretchedWindow()
  724. {
  725. if( (pStretch->baseWidth >= size.width) &&
  726. (pStretch->baseHeight >= size.height) ) {
  727. return FALSE;
  728. }
  729. return TRUE;
  730. }
  731. /**************************************************************************\
  732. * SetSSWindowPos
  733. *
  734. * Set new size and position for an SSW
  735. *
  736. \**************************************************************************/
  737. void
  738. SSW::SetSSWindowPos()
  739. {
  740. SetSSWindowPos( 0 );
  741. }
  742. void
  743. SSW::SetSSWindowPos( int flags )
  744. {
  745. if( hwnd ) {
  746. SetWindowPos(hwnd, 0, pos.x, pos.y,
  747. size.width, size.height,
  748. SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE | flags );
  749. // Note: If flags does not specify SWP_NOREDRAW, this generates a WM_PAINT
  750. // msg for the entire window region
  751. } else if( psswParent && !pStretch ) {
  752. // Set viewport for new position
  753. // (mf: if pStretch, shouldn't need to do anything, as viewport should
  754. // have been already set to the bitmap)
  755. int posy = GLPosY();
  756. glViewport( pos.x, posy, size.width, size.height );
  757. glScissor( pos.x, posy, size.width, size.height );
  758. glAddSwapHintRect( pos.x, posy, size.width, size.height );
  759. }
  760. }
  761. /******************************Public*Routine******************************\
  762. * SetAspectRatio
  763. *
  764. * Resize a child window to conform to the supplied aspect ratio. We do this by
  765. * maintaining the existing width, and adjusting the height.
  766. *
  767. * Window resize seems to be executed synchronously, so gl should be able to
  768. * immediately validate its buffer dimensions (we count on it).
  769. *
  770. * Returns TRUE if new height is different from last, else FALSE.
  771. \**************************************************************************/
  772. BOOL
  773. SSW::SetAspectRatio( FLOAT fAspect )
  774. {
  775. if( !psswParent )
  776. return FALSE;
  777. int oldHeight;
  778. UINT uFlags = 0;
  779. // Check for zero fAspect
  780. if( fAspect == 0.0f ) fAspect = 1.0f;
  781. oldHeight = size.height;
  782. // Set the new height, based on desired aspect ratio
  783. size.height = (int) ((FLOAT) size.width / fAspect);
  784. // make sure new height not TOO big!
  785. ValidateChildSize();
  786. if( size.height == oldHeight )
  787. // no change
  788. return FALSE;
  789. // make sure current position still valid when height changes
  790. if( !bValidateChildPos() ) {
  791. // current position OK, don't need to move it
  792. uFlags |= SWP_NOMOVE;
  793. }
  794. SetSSWindowPos( uFlags );
  795. // ! remember not to call the client's ReshapeFunc here, as SetAspectRatio
  796. // may be called by the client in response to a window resize, resulting in
  797. // an infinite loop
  798. //mf: but if there is no size change (above) we return, avoiding the
  799. // infinite loop
  800. if( !hwnd )
  801. // Need to call Reshape, since win32 system won't send WM_SIZE. Need
  802. // to fix to avoid possible infinite loops
  803. Reshape();
  804. return TRUE;
  805. }
  806. /**************************************************************************\
  807. * CalcNextWindowPos
  808. *
  809. * Calculate the next position for a moving window, using the pMotion data.
  810. * If the new position would cause the window to bounce off the
  811. * edge of its parent, return TRUE.
  812. *
  813. \**************************************************************************/
  814. BOOL
  815. SSW::CalcNextWindowPos()
  816. {
  817. POINT2D *fpos = &pMotion->pos;
  818. IPOINT2D *ipos = &pos;
  819. POINT2D *posInc = &pMotion->posInc;
  820. POINT2D *posIncV = &pMotion->posIncVary;
  821. POINT2D *posIncCur = &pMotion->posIncCur;
  822. BOOL bounce = FALSE;
  823. if( !psswParent )
  824. return FALSE;
  825. // Compute the next window position.
  826. fpos->x += posIncCur->x;
  827. fpos->y += posIncCur->y;
  828. ipos->x = (int) fpos->x;
  829. ipos->y = (int) fpos->y;
  830. if ( (ipos->x + size.width) > psswParent->size.width) {
  831. // Right hit
  832. ipos->x = psswParent->size.width - size.width;
  833. fpos->x = (float) ipos->x;
  834. posIncCur->x =
  835. - ss_fRand( posInc->x - posIncV->x, posInc->x + posIncV->x );
  836. if( posIncCur->x > -0.5f ) posIncCur->x = -0.5f;
  837. bounce = TRUE;
  838. } else if (ipos->x < 0) {
  839. // Left hit
  840. ipos->x = 0;
  841. fpos->x = 0.0f;
  842. posIncCur->x =
  843. ss_fRand( posInc->x - posIncV->x, posInc->x + posIncV->x );
  844. if( posIncCur->x < 0.5f ) posIncCur->x = 0.5f;
  845. bounce = TRUE;
  846. }
  847. if ( (ipos->y + size.height) > psswParent->size.height) {
  848. // Bottom hit
  849. ipos->y = psswParent->size.height - size.height;
  850. fpos->y = (float) (ipos->y);
  851. posIncCur->y =
  852. - ss_fRand( posInc->y - posIncV->y, posInc->y + posIncV->y );
  853. if( posIncCur->y > -0.5f ) posIncCur->y = -0.5f;
  854. bounce = TRUE;
  855. } else if (ipos->y < 0) {
  856. // Top hit
  857. ipos->y = 0;
  858. fpos->y = 0.0f;
  859. posIncCur->y =
  860. ss_fRand( posInc->y - posIncV->y, posInc->y + posIncV->y );
  861. if( posIncCur->y < 0.5f ) posIncCur->y = 0.5f;
  862. bounce = TRUE;
  863. }
  864. return bounce;
  865. }
  866. /**************************************************************************\
  867. * MoveSSWindow
  868. *
  869. * This is the function that moves the OpenGL window around, causing it to
  870. * bounce around. Each time the window is moved, the contents of the
  871. * window are updated from the hidden (or back) buffer by SwapBuffers().
  872. *
  873. * The bRedrawBg flag determines whether the area that was covered by the old
  874. * position should be updated by the parent window.
  875. *
  876. \**************************************************************************/
  877. void
  878. SSW::MoveSSWindow( BOOL bRedrawBg )
  879. {
  880. BOOL bounce;
  881. int flags = SWP_NOSIZE;
  882. // Synchronize with OpenGL. Flush OpenGL commands and wait for completion.
  883. glFinish();
  884. // Move the window
  885. bounce = CalcNextWindowPos();
  886. if( bounce && FloaterBounceFunc )
  887. // The window bounced off one of the sides
  888. // ! This function should *not* be used for rendering - for
  889. // informational purposes only (.e.g. changing the spin of a
  890. // rotating object).
  891. (*FloaterBounceFunc)( DataPtr );
  892. if( !bRedrawBg )
  893. flags |= SWP_NOREDRAW;
  894. SetSSWindowPos( flags );
  895. }
  896. /**************************************************************************\
  897. * UpdateWindow
  898. *
  899. * Update the window
  900. *
  901. * Ccurrently this assumes all windows are being animated (i.e. not showing
  902. * a static image)
  903. *
  904. * Things *must* happen in the order defined here, so they work on generic as
  905. * well as hardware implementations.
  906. * Note: Move must happen after SwapBuf, and will cause some encroaching on
  907. * the current display, as the parent window repaints after the move. Therefore
  908. * apps must take care to leave an empty border around their rendered image,
  909. * equal to the maximum window move delta.
  910. *
  911. \**************************************************************************/
  912. void
  913. SSW::UpdateWindow()
  914. {
  915. // update any children first
  916. PSSW pssw = psswChildren;
  917. while( pssw ) {
  918. pssw->UpdateWindow();
  919. pssw = pssw->psswSibling;
  920. }
  921. //mf: semi-kluge
  922. // If this window is a subWindow in a non-generic implementation, the
  923. // background of the parent may be invalid (this may eventually be
  924. // useful for regular windows, which is why we don't && !hwnd)
  925. if( psswParent &&
  926. psswParent->bValidateBg &&
  927. pGLc &&
  928. !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) )
  929. {
  930. // Clear the entire parent window
  931. // mf: I think this is only needed for double-buffered schemes, since
  932. // the windowing system should repaint the front buffer in this case.
  933. glDisable( GL_SCISSOR_TEST );
  934. glClear( GL_COLOR_BUFFER_BIT );
  935. glEnable( GL_SCISSOR_TEST );
  936. psswParent->bValidateBg = FALSE;
  937. }
  938. if( !UpdateFunc )
  939. return;
  940. // bDoubleBuf and pStretch should be mutually exclusive...
  941. if( bDoubleBuf || pStretch ) {
  942. UpdateDoubleBufWin();
  943. } else {
  944. //mf: ? where's the clearing here ? (true, no one uses this path...)
  945. if( pMotion )
  946. MoveSSWindow( TRUE );
  947. (*UpdateFunc)( DataPtr );
  948. }
  949. }
  950. /**************************************************************************\
  951. * UpdateDoubleBufWin
  952. *
  953. * This is used when moving a double buffered window around. It will
  954. * work for all configurations.
  955. *
  956. \**************************************************************************/
  957. void
  958. SSW::UpdateDoubleBufWin()
  959. {
  960. if( !hwnd ) {
  961. UpdateDoubleBufSubWin();
  962. return;
  963. }
  964. RECT updateRect;
  965. // Move the window
  966. if( pMotion ) {
  967. // Save child update rect before move
  968. GetSSWindowRect( &updateRect );
  969. // Move window, without repainting exposed area
  970. MoveSSWindow( FALSE );
  971. }
  972. // Update the back buffer
  973. (*UpdateFunc)( DataPtr );
  974. if( pMotion ) {
  975. // (pMotion will be NULL if this window has no parent)
  976. if( hwnd ) {
  977. // Paint the exposed area with bg brush (the current image will
  978. // be partially erased momentarily, until the SwapBuffers() call
  979. // comes through)
  980. // (This rect should be clipped to our new window position...)
  981. DrawGdiRect( psswParent->hdc, gpss->hbrBg, &updateRect );
  982. } else {
  983. //mf: currently this path not possible, since if !hwnd, we use one of the
  984. // UpdateDoubleBufSubWin* functions
  985. SS_WARNING( "SSW::UpdateDoubleBufWin: no hwnd\n" );
  986. // sub-window case : need to do our own clipping
  987. RECT newRect;
  988. GetSSWindowRect( &newRect );
  989. DrawGdiDeltaRect( psswParent->hdc, gpss->hbrBg, &updateRect, &newRect );
  990. }
  991. }
  992. // Swap to the new window position
  993. SwapSSBuffers();
  994. }
  995. /**************************************************************************\
  996. * UpdateDoubleBufSubWin
  997. *
  998. * Used for generic double buffered gl sub-windows.
  999. *
  1000. \**************************************************************************/
  1001. void
  1002. SSW::UpdateDoubleBufSubWin()
  1003. {
  1004. GLRECT curRect, newRect;
  1005. // AddSwapHintRect for current position
  1006. glAddSwapHintRect( pos.x, GLPosY(), size.width, size.height );
  1007. if( pMotion ) {
  1008. // Save current rect
  1009. curRect.x = pos.x;
  1010. curRect.y = GLPosY();
  1011. curRect.width = size.width;
  1012. curRect.height = size.height;
  1013. // Move window, without repainting exposed area
  1014. MoveSSWindow( FALSE );
  1015. // Get new rect
  1016. newRect.x = pos.x;
  1017. newRect.y = GLPosY();
  1018. newRect.width = size.width;
  1019. newRect.height = size.height;
  1020. DrawGLDeltaRect( &curRect, &newRect );
  1021. // Have to consider previous rect for ICD or MCD
  1022. if( !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) ) {
  1023. DrawGLDeltaRect( &lastRect, &newRect );
  1024. lastRect = curRect;
  1025. }
  1026. // Reset scissor to new rect (this *was* set by MoveSSWindow, but
  1027. // DrawGLDeltaRect sets scissor to do its clearing
  1028. glScissor( newRect.x, newRect.y, newRect.width, newRect.height );
  1029. }
  1030. // Update the back buffer
  1031. (*UpdateFunc)( DataPtr );
  1032. // Swap to the new window position
  1033. SwapSSBuffers();
  1034. }
  1035. /******************************Public*Routine******************************\
  1036. * RandomWindowPos
  1037. *
  1038. * Sets a new random window position and motion
  1039. *
  1040. \**************************************************************************/
  1041. void
  1042. SSW::RandomWindowPos()
  1043. {
  1044. if( psswParent ) {
  1045. if( !hwnd ) {
  1046. // sub-window : manually clear old window rect
  1047. if( bDoubleBuf ) {
  1048. glClear( GL_COLOR_BUFFER_BIT );
  1049. } else {
  1050. RECT oldRect;
  1051. GetSSWindowRect( &oldRect );
  1052. DrawGdiRect( psswParent->hdc, gpss->hbrBg, &oldRect );
  1053. }
  1054. }
  1055. // Calc and set new position
  1056. pos.x = ss_iRand2( 0, (psswParent->size.width - size.width) );
  1057. pos.y = ss_iRand2( 0, (psswParent->size.height - size.height) );
  1058. SetSSWindowPos( SWP_NOSIZE );
  1059. // Reset motion
  1060. if( pMotion )
  1061. ResetMotion();
  1062. }
  1063. }
  1064. /**************************************************************************\
  1065. * ResetMotion
  1066. *
  1067. * Calculate a random position and motion vector for the floater window
  1068. * Note that a floating point position is maintained for DDA window movement
  1069. *
  1070. \**************************************************************************/
  1071. void
  1072. SSW::ResetMotion()
  1073. {
  1074. if( !psswParent || !pMotion )
  1075. // Only child windows can be reset
  1076. return;
  1077. // Set floating point pos also, for DDA
  1078. pMotion->pos.x = (float) pos.x;
  1079. pMotion->pos.y = (float) pos.y;
  1080. // also reset the window motion directions
  1081. if( ss_iRand(2) ) // 0 or 1
  1082. pMotion->posIncCur.x = - pMotion->posIncCur.x;
  1083. if( ss_iRand(2) )
  1084. pMotion->posIncCur.y = - pMotion->posIncCur.y;
  1085. }
  1086. /**************************************************************************\
  1087. * ValidateChildSize
  1088. *
  1089. * Make sure it's not bigger than its parent
  1090. *
  1091. \**************************************************************************/
  1092. void
  1093. SSW::ValidateChildSize()
  1094. {
  1095. if( !psswParent )
  1096. return;
  1097. SS_CLAMP_TO_RANGE2( size.width, 0, psswParent->size.width );
  1098. SS_CLAMP_TO_RANGE2( size.height, 0, psswParent->size.height );
  1099. }
  1100. /**************************************************************************\
  1101. * bValidateChildPos
  1102. *
  1103. * Make sure that with the current window position, none of the floating
  1104. * window extends beyond the parent window.
  1105. *
  1106. \**************************************************************************/
  1107. BOOL
  1108. SSW::bValidateChildPos()
  1109. {
  1110. BOOL bRet = FALSE;
  1111. if( !psswParent )
  1112. return FALSE;
  1113. if ( (pos.x + size.width) > psswParent->size.width) {
  1114. pos.x = psswParent->size.width - size.width;
  1115. bRet = TRUE;
  1116. }
  1117. if ( (pos.y + size.height) > psswParent->size.height) {
  1118. pos.y = psswParent->size.height - size.height;
  1119. bRet = TRUE;
  1120. }
  1121. return bRet;
  1122. }
  1123. /**************************************************************************\
  1124. * GetSSWindowRect
  1125. *
  1126. * Return window position and size in supplied RECT structure
  1127. *
  1128. * mf: this rect is relative to the parent
  1129. \**************************************************************************/
  1130. void
  1131. SSW::GetSSWindowRect( LPRECT lpRect )
  1132. {
  1133. lpRect->left = pos.x;
  1134. lpRect->top = pos.y;
  1135. lpRect->right = pos.x + size.width;
  1136. lpRect->bottom = pos.y + size.height;
  1137. }
  1138. /**************************************************************************\
  1139. * GLPosY
  1140. *
  1141. * Return y-coord of window position in GL coordinates (a win32 window position
  1142. * (starts from top left, while GL starts from bottom left)
  1143. *
  1144. \**************************************************************************/
  1145. int
  1146. SSW::GLPosY()
  1147. {
  1148. if( !psswParent )
  1149. return 0;
  1150. return psswParent->size.height - size.height - pos.y;
  1151. }
  1152. /**************************************************************************\
  1153. * SwapStretchBuffers
  1154. *
  1155. * Swaps from the stretch buffer to the GL window, using StretchBlt
  1156. *
  1157. \**************************************************************************/
  1158. void
  1159. SSW::SwapStretchBuffers()
  1160. {
  1161. SS_BITMAP *pssbm = &pStretch->ssbm;
  1162. if( (size.width == pssbm->size.width) &&
  1163. (size.height == pssbm->size.height) ) // buffers same size
  1164. {
  1165. BitBlt(hdc, 0, 0, size.width, size.height,
  1166. pssbm->hdc, 0, 0, SRCCOPY);
  1167. }
  1168. else
  1169. {
  1170. StretchBlt(hdc, 0, 0, size.width, size.height,
  1171. pssbm->hdc, 0, 0, pssbm->size.width, pssbm->size.height,
  1172. SRCCOPY);
  1173. }
  1174. GdiFlush();
  1175. }
  1176. /**************************************************************************\
  1177. * SwapBuffers
  1178. *
  1179. * Wrapper for SwapBuffers / SwapStretchBuffers
  1180. *
  1181. \**************************************************************************/
  1182. void
  1183. SSW::SwapSSBuffers()
  1184. {
  1185. if( pStretch )
  1186. SwapStretchBuffers();
  1187. else if( bDoubleBuf ) {
  1188. SwapBuffers( hdc );
  1189. }
  1190. }
  1191. /**************************************************************************\
  1192. * Reshape
  1193. *
  1194. * Reshape wrapper
  1195. * Sends reshape msg to screen saver
  1196. * This is the size of the surface that gl renders onto, which can be a bitmap.
  1197. *
  1198. \**************************************************************************/
  1199. void
  1200. SSW::Reshape()
  1201. {
  1202. // Point to size of window, or bitmap if it has one
  1203. ISIZE *pSize = &size;
  1204. if( pStretch )
  1205. pSize = &pStretch->ssbm.size;
  1206. // If the window has an hrc, set default viewport
  1207. if( hrc ) {
  1208. if( hwnd )
  1209. glViewport( 0, 0, pSize->width, pSize->height );
  1210. else if ( psswParent ) {
  1211. // sub-window (only 1 level of sub-windowing supported)
  1212. //mf: klugey ? - should take into account non-GL and single buffer...
  1213. #if 1
  1214. // clear entire window to black
  1215. glDisable( GL_SCISSOR_TEST );
  1216. glClear( GL_COLOR_BUFFER_BIT );
  1217. glEnable( GL_SCISSOR_TEST );
  1218. #endif
  1219. // Convert win32 y-coord to GL
  1220. glViewport( pos.x, GLPosY(), pSize->width, pSize->height );
  1221. }
  1222. }
  1223. if( ReshapeFunc ) {
  1224. (*ReshapeFunc)( pSize->width, pSize->height, DataPtr );
  1225. }
  1226. }
  1227. /******************************Public*Routine******************************\
  1228. * GdiClear
  1229. *
  1230. * Clears window using Gdi FillRect
  1231. \**************************************************************************/
  1232. void
  1233. SSW::GdiClear()
  1234. {
  1235. if( !hdc )
  1236. return;
  1237. RECT rect;
  1238. //mf: this should use GetClientRect
  1239. GetSSWindowRect( &rect );
  1240. FillRect( hdc, &rect, gpss->hbrBg );
  1241. GdiFlush();
  1242. }
  1243. /******************************Public*Routine******************************\
  1244. * MyAddSwapHintRect
  1245. *
  1246. \**************************************************************************/
  1247. static void _stdcall
  1248. MyAddSwapHintRect(GLint xs, GLint ys, GLint xe, GLint ye)
  1249. {
  1250. return;
  1251. }
  1252. /******************************Public*Routine******************************\
  1253. * QueryAddSwapHintRectWIN
  1254. *
  1255. \**************************************************************************/
  1256. static void
  1257. ss_QueryAddSwapHintRect()
  1258. {
  1259. glAddSwapHintRect = (PFNGLADDSWAPHINTRECTWINPROC)
  1260. wglGetProcAddress("glAddSwapHintRectWIN");
  1261. if (glAddSwapHintRect == NULL) {
  1262. glAddSwapHintRect = MyAddSwapHintRect;
  1263. }
  1264. }
  1265. /******************************Public*Routine******************************\
  1266. * DrawGdiDeltaRect
  1267. *
  1268. * Draw the exposed area by transition from rect1 to rect2
  1269. \**************************************************************************/
  1270. static void
  1271. DrawGdiDeltaRect( HDC hdc, HBRUSH hbr, RECT *pRect1, RECT *pRect2 )
  1272. {
  1273. if( (pRect1 == NULL) || (pRect2 == NULL) ) {
  1274. SS_WARNING( "DrawGdiDeltaRect : one or both rects are NULL\n" );
  1275. return;
  1276. }
  1277. // Draw 2 rects
  1278. RECT rect;
  1279. // Rect exposed in x-direction:
  1280. rect.top = pRect1->top;
  1281. rect.bottom = pRect1->bottom;
  1282. if( pRect2->left > pRect1->left ) {
  1283. // moving right
  1284. rect.left = pRect1->left;
  1285. rect.right = pRect2->left;
  1286. } else {
  1287. // moving left
  1288. rect.left = pRect2->right;
  1289. rect.right = pRect1->right;
  1290. }
  1291. FillRect( hdc, &rect, hbr );
  1292. // Rect exposed in y-direction:
  1293. rect.left = pRect1->left;
  1294. rect.right = pRect1->right;
  1295. if( pRect2->bottom > pRect1->bottom ) {
  1296. // moving down
  1297. rect.top = pRect1->top;
  1298. rect.bottom = pRect2->top;
  1299. } else {
  1300. // moving up
  1301. rect.top = pRect2->bottom;
  1302. rect.bottom = pRect1->bottom;
  1303. }
  1304. FillRect( hdc, &rect, hbr );
  1305. GdiFlush();
  1306. }
  1307. /******************************Public*Routine******************************\
  1308. * DrawGLDeltaRect
  1309. *
  1310. * Draw the exposed area by transition from rect1 to rect2
  1311. \**************************************************************************/
  1312. static void
  1313. DrawGLDeltaRect( GLRECT *pRect1, GLRECT *pRect2 )
  1314. {
  1315. if( (pRect1 == NULL) || (pRect2 == NULL) ) {
  1316. SS_WARNING( "DrawGLDeltaRect : one or both rects are NULL\n" );
  1317. return;
  1318. }
  1319. // Draw 2 rects :
  1320. //mf: !!! this assumes rect1 and rect2 have same dimensions !
  1321. GLRECT rect;
  1322. // Rect exposed in x-direction:
  1323. rect.height = pRect1->height;
  1324. rect.y = pRect1->y;
  1325. if( pRect2->x > pRect1->x ) {
  1326. // moving right
  1327. rect.width = pRect2->x - pRect1->x;
  1328. rect.x = pRect1->x;
  1329. } else {
  1330. // moving left
  1331. rect.width = pRect1->x - pRect2->x;
  1332. rect.x = pRect2->x + pRect2->width;
  1333. }
  1334. glScissor( rect.x, rect.y, rect.width, rect.height );
  1335. glClear( GL_COLOR_BUFFER_BIT );
  1336. // Rect exposed in y-direction:
  1337. rect.width = pRect1->width;
  1338. rect.x = pRect1->x;
  1339. if( pRect2->y > pRect1->y ) {
  1340. // moving up
  1341. rect.height = pRect2->y - pRect1->y;
  1342. rect.y = pRect1->y;
  1343. } else {
  1344. // moving down
  1345. rect.height = pRect1->y - pRect2->y;
  1346. rect.y = pRect2->y + pRect2->height;
  1347. }
  1348. glScissor( rect.x, rect.y, rect.width, rect.height );
  1349. glClear( GL_COLOR_BUFFER_BIT );
  1350. }