Source code of Windows XP (NT5)
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.

1629 lines
45 KiB

  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. Do the same thing if a
  418. // monitor configuration is detected, since only the generic implementation
  419. // will work properly in this case on all displays.
  420. if( ss_fConfigMode() || (GetSystemMetrics(SM_CMONITORS) > 1) )
  421. pfFlags |= SS_GENERIC_UNACCELERATED_BIT;
  422. bDoubleBuf = SS_HAS_DOUBLEBUF( pfFlags );
  423. if( !SSU_SetupPixelFormat( hdc, pfFlags, &pfd ) )
  424. return NULL_RC;
  425. // Update pGLc->pfFlags based on pfd returned
  426. // !!! mf: klugey, fix after SUR
  427. // (for now, the only ones we care about are the generic/accelerated flags)
  428. if( (pfd.dwFlags & (PFD_GENERIC_FORMAT|PFD_GENERIC_ACCELERATED))
  429. == PFD_GENERIC_FORMAT )
  430. pGLc->pfFlags |= SS_GENERIC_UNACCELERATED_BIT;
  431. if( SSU_bNeedPalette( &pfd ) ) {
  432. // Note: even if bStretch, need to set up palette here so they match
  433. if( !gpss->pssPal ) {
  434. SS_PAL *pssPal;
  435. BOOL bTakeOverPalette = ss_fFullScreenMode() ? TRUE : FALSE;
  436. // The global palette has not been created yet - do it
  437. // SS_PAL creation requires pixel format descriptor for color bit
  438. // information, etc. (the pfd is cached in SS_PAL, since for
  439. // palette purposes it is the same for all windows)
  440. pssPal = new SS_PAL( hdc, &pfd, bTakeOverPalette );
  441. if( !pssPal )
  442. return NULL_RC;
  443. // Set approppriate palette manage proc
  444. if( ss_fFullScreenMode() )
  445. pssPal->paletteManageProc = FullScreenPaletteManageProc;
  446. else
  447. // use regular palette manager proc
  448. pssPal->paletteManageProc = PaletteManageProc;
  449. gpss->pssPal = pssPal;
  450. }
  451. // Realize the global palette in this window
  452. //mf: assume we're realizing in foreground
  453. HWND hwndPal = hwnd ? hwnd : psswParent ? psswParent->hwnd : NULL;
  454. if( hwndPal )
  455. gpss->pssPal->Realize( hwndPal, hdc, FALSE );
  456. }
  457. if( pStretch ) {
  458. // Stretch blt mode: For every frame, we'll be doing a StretchBlt
  459. // from a DIB to the screen. Need to set up a compatible memdc.
  460. SS_BITMAP *pssbm;
  461. pssbm = &pStretch->ssbm;
  462. pssbm->hdc = CreateCompatibleDC(hdc);
  463. if( !pssbm->hdc )
  464. return NULL_RC;
  465. ResizeStretch(); // this creates the DIB Section
  466. pfFlags = 0;
  467. pfFlags |= SS_BITMAP_BIT;
  468. if( !SSU_SetupPixelFormat( pssbm->hdc, pfFlags, &pfd ) ) {
  469. return NULL_RC;
  470. }
  471. //mf: this ppfd's palette bits must match the window's !!
  472. // If window needs palette, so does bitmap...
  473. if( gpss->pssPal ) {
  474. SS_PAL *pssPal = gpss->pssPal;
  475. extern void ssw_UpdateDIBColorTable( HDC, HDC );
  476. ssw_UpdateDIBColorTable( pssbm->hdc, hdc );
  477. }
  478. hgldc = pssbm->hdc;
  479. } else {
  480. hgldc = hdc;
  481. }
  482. if( pGLc->hrc ) {
  483. // Use the supplied hrc
  484. hrc = pGLc->hrc;
  485. // Set flag so we don't delete this borrowed hrc when the SSW terminates
  486. wFlags |= SS_HRC_PROXY_BIT;
  487. } else
  488. // Create a new hrc
  489. hrc = wglCreateContext(hgldc);
  490. if( !hrc || !wglMakeCurrent(hgldc, hrc) ) {
  491. SS_WARNING( "SSW::hrcSetupGL : hrc context failure\n" );
  492. return NULL_RC;
  493. }
  494. if( !hwnd && (bDoubleBuf || pStretch) ) {
  495. // enable scissoring
  496. glEnable( GL_SCISSOR_TEST );
  497. if( !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) ) {
  498. // MCD or ICD, possible hardware implementation - we maintain
  499. // a lastRect to handle SwapBuffer issues
  500. lastRect.x = lastRect.y = lastRect.width = lastRect.height = 0;
  501. }
  502. }
  503. SS_DBGLEVEL2( SS_LEVEL_INFO,
  504. "SSW::hrcSetupGL: wglMakeCurrent( hrc=0x%x, hwnd=0x%x )\n", hrc, hwnd );
  505. //mf: Note that these queries are based on a single gl window screen saver. In
  506. // a more complicated scenario, these capabilities could be queried on a
  507. // per-window basis (since support could vary with pixel formats).
  508. // Query the GL version - sets support for any new (e.g. 1.1) functionality
  509. ss_QueryGLVersion();
  510. // Query paletted texture extension
  511. ss_QueryPalettedTextureEXT();
  512. // Query the AddSwapHintRect WIN extension
  513. ss_QueryAddSwapHintRect();
  514. // Pull in any Func's that were already defined (for compatibility with
  515. // old mechanism)
  516. InitFunc = gInitFunc;
  517. UpdateFunc = gUpdateFunc;
  518. ReshapeFunc = gReshapeFunc;
  519. RepaintFunc = gRepaintFunc;
  520. FloaterBounceFunc = gFloaterBounceFunc;
  521. FinishFunc = gFinishFunc;
  522. DataPtr = gDataPtr;
  523. return hrc;
  524. }
  525. /**************************************************************************\
  526. * MakeCurrent
  527. *
  528. * Call wglMakeCurrent for this window's hrc. Note: an ss client may have
  529. * more than one hrc (e.g. pipes), in which case it is the client's
  530. * responsibility to make current.
  531. \**************************************************************************/
  532. void
  533. SSW::MakeCurrent()
  534. {
  535. if( ! wglMakeCurrent( hdc, hrc ) ) {
  536. SS_WARNING( "SSW::MakeCurrent : wglMakeCurrent failure\n" );
  537. }
  538. }
  539. /**************************************************************************\
  540. * InitGL
  541. *
  542. * Call the window's GL Init Func
  543. *
  544. * Priority is raised to expedite any initialization (e.g. loading and
  545. * processing textures can take a while.
  546. *
  547. * A Reshape msg is sent to the client ss, as this is required for setting
  548. * glViewport, etc.
  549. \**************************************************************************/
  550. void
  551. SSW::InitGL()
  552. {
  553. PSSW psswChild = psswChildren;
  554. // Configure the window for GL if pGLc non-NULL
  555. if( pGLc && (! ConfigureForGL()) ) {
  556. // This is fatal for this window - if it is the main window,
  557. // the ss will terminate
  558. if( hwnd )
  559. PostMessage( hwnd, WM_CLOSE, 0, 0l );
  560. return;
  561. }
  562. // If window configured for GL, hrc will have been set...
  563. // Call the InitFunc
  564. if( hrc && InitFunc ) {
  565. DWORD oldPriority;
  566. // Bump up priority during initialization phase
  567. oldPriority = GetPriorityClass( GetCurrentProcess() );
  568. SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS );
  569. SS_DBGLEVEL1( SS_LEVEL_INFO,
  570. "SSW::InitGL: Calling client GLInit for 0x%x\n", hwnd );
  571. (*InitFunc)( DataPtr );
  572. // restore original priority
  573. SetPriorityClass( GetCurrentProcess(), oldPriority );
  574. }
  575. /* Send another Reshape, since initial one triggered by window
  576. * creation would have been received before GL init'd
  577. */
  578. Reshape();
  579. // Next, init any child windows. This has to be done after the parent
  580. // window initialization.
  581. while( psswChild ) {
  582. if( psswChild->hwnd )
  583. SendMessage( psswChild->hwnd, SS_WM_INITGL, 0, 0 );
  584. else
  585. // Must be a logical sub-window
  586. psswChild->InitGL();
  587. psswChild = psswChild->psswSibling;
  588. }
  589. }
  590. /**************************************************************************\
  591. * ResizeStretch
  592. *
  593. * Resize the compatible bitmap for stretch blt mode
  594. *
  595. * There are 2 sizing modes. If bRatioMode, then we set the bitmap size
  596. * by dividing the window dimensions by the supplied ratios. In this case,
  597. * the base* values set a lower limit for the bitmap dimensions. Otherwise, the
  598. * base* values determine the bitmap dimensions.
  599. *
  600. * Feb. 12, 96 : [marcfo]
  601. *
  602. \**************************************************************************/
  603. void
  604. SSW::ResizeStretch()
  605. {
  606. RECT rc;
  607. HBITMAP hbmNew;
  608. PVOID pvBits;
  609. int width, height;
  610. int cwidth, cheight; // client area size
  611. SS_BITMAP *pssbm = &pStretch->ssbm;
  612. cwidth = size.width;
  613. cheight = size.height;
  614. if( pStretch->bRatioMode ) {
  615. width = (int) ( (float)cwidth / pStretch->widthRatio );
  616. height = (int) ( (float)cheight / pStretch->heightRatio );
  617. if( width < pStretch->baseWidth )
  618. width = pStretch->baseWidth;
  619. if( height < pStretch->baseHeight )
  620. height = pStretch->baseHeight ;
  621. } else {
  622. width = pStretch->baseWidth;
  623. height = pStretch->baseHeight;
  624. }
  625. // Limit width, height to window dimensions
  626. if( width > cwidth )
  627. width = cwidth;
  628. if( height > cheight )
  629. height = cheight;
  630. // If same size, get out
  631. if( (width == pssbm->size.width) && (height == pssbm->size.height) )
  632. return;
  633. pssbm->size.width = width;
  634. pssbm->size.height = height;
  635. #if 1
  636. // Use system palette
  637. hbmNew = SSDIB_CreateCompatibleDIB(hdc, NULL, width, height, &pvBits);
  638. #else
  639. // Use log palette
  640. hbmNew = SSDIB_CreateCompatibleDIB(hdc,
  641. gpss->pssPal ? gpss->pssPal->hPal : NULL,
  642. width, height, &pvBits);
  643. #endif
  644. if (hbmNew)
  645. {
  646. if (pssbm->hbm != (HBITMAP) 0)
  647. {
  648. SelectObject( pssbm->hdc, pssbm->hbmOld );
  649. DeleteObject( pssbm->hbm );
  650. }
  651. pssbm->hbm = hbmNew;
  652. pssbm->hbmOld = (HBITMAP) SelectObject( pssbm->hdc, pssbm->hbm );
  653. }
  654. }
  655. /**************************************************************************\
  656. * Resize
  657. *
  658. * Resize wrapper
  659. *
  660. * Called in response to WM_SIZE.
  661. *
  662. \**************************************************************************/
  663. void
  664. SSW::Resize( int width, int height )
  665. {
  666. size.width = width;
  667. size.height = height;
  668. if( pStretch ) {
  669. // May have to resize associated bitmap
  670. ResizeStretch();
  671. }
  672. if( psswChildren ) {
  673. // May need to resize any children
  674. PSSW pssw = psswChildren;
  675. while( pssw ) {
  676. // Get new size/motion for the floater
  677. pssw->GetChildInfo();
  678. pssw->SetSSWindowPos();
  679. if( !pssw->hwnd ) {
  680. // Handle sub-window case
  681. // Need to call Reshape, since win32 system won't send WM_SIZE.
  682. pssw->Reshape();
  683. }
  684. pssw = pssw->psswSibling;
  685. }
  686. }
  687. Reshape();
  688. }
  689. /**************************************************************************\
  690. * Repaint
  691. *
  692. * Repaint wrapper
  693. *
  694. * Called in response to WM_PAINT.
  695. *
  696. \**************************************************************************/
  697. #define NULL_UPDATE_RECT( pRect ) \
  698. ( ((pRect)->left == 0) && \
  699. ((pRect)->right == 0) && \
  700. ((pRect)->top == 0) && \
  701. ((pRect)->bottom == 0) )
  702. void
  703. SSW::Repaint( BOOL bCheckUpdateRect )
  704. {
  705. if( !hwnd )
  706. return;
  707. RECT rect, *pRect = NULL;
  708. if( bCheckUpdateRect ) {
  709. GetUpdateRect( hwnd, &rect, FALSE );
  710. // mf: Above supposed to return NULL if rect is all 0's,
  711. // but this doesn't happen
  712. if( NULL_UPDATE_RECT( &rect ) )
  713. return;
  714. pRect = &rect;
  715. }
  716. if( RepaintFunc )
  717. (*RepaintFunc)( pRect, DataPtr );
  718. }
  719. /**************************************************************************\
  720. * NeedStretchedWindow
  721. *
  722. * Check if stretch mode is necessary
  723. *
  724. \**************************************************************************/
  725. BOOL
  726. SSW::NeedStretchedWindow()
  727. {
  728. if( (pStretch->baseWidth >= size.width) &&
  729. (pStretch->baseHeight >= size.height) ) {
  730. return FALSE;
  731. }
  732. return TRUE;
  733. }
  734. /**************************************************************************\
  735. * SetSSWindowPos
  736. *
  737. * Set new size and position for an SSW
  738. *
  739. \**************************************************************************/
  740. void
  741. SSW::SetSSWindowPos()
  742. {
  743. SetSSWindowPos( 0 );
  744. }
  745. void
  746. SSW::SetSSWindowPos( int flags )
  747. {
  748. if( hwnd ) {
  749. SetWindowPos(hwnd, 0, pos.x, pos.y,
  750. size.width, size.height,
  751. SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE | flags );
  752. // Note: If flags does not specify SWP_NOREDRAW, this generates a WM_PAINT
  753. // msg for the entire window region
  754. } else if( psswParent && !pStretch ) {
  755. // Set viewport for new position
  756. // (mf: if pStretch, shouldn't need to do anything, as viewport should
  757. // have been already set to the bitmap)
  758. int posy = GLPosY();
  759. glViewport( pos.x, posy, size.width, size.height );
  760. glScissor( pos.x, posy, size.width, size.height );
  761. glAddSwapHintRect( pos.x, posy, size.width, size.height );
  762. }
  763. }
  764. /******************************Public*Routine******************************\
  765. * SetAspectRatio
  766. *
  767. * Resize a child window to conform to the supplied aspect ratio. We do this by
  768. * maintaining the existing width, and adjusting the height.
  769. *
  770. * Window resize seems to be executed synchronously, so gl should be able to
  771. * immediately validate its buffer dimensions (we count on it).
  772. *
  773. * Returns TRUE if new height is different from last, else FALSE.
  774. \**************************************************************************/
  775. BOOL
  776. SSW::SetAspectRatio( FLOAT fAspect )
  777. {
  778. if( !psswParent )
  779. return FALSE;
  780. int oldHeight;
  781. UINT uFlags = 0;
  782. // Check for zero fAspect
  783. if( fAspect == 0.0f ) fAspect = 1.0f;
  784. oldHeight = size.height;
  785. // Set the new height, based on desired aspect ratio
  786. size.height = (int) ((FLOAT) size.width / fAspect);
  787. // make sure new height not TOO big!
  788. ValidateChildSize();
  789. if( size.height == oldHeight )
  790. // no change
  791. return FALSE;
  792. // make sure current position still valid when height changes
  793. if( !bValidateChildPos() ) {
  794. // current position OK, don't need to move it
  795. uFlags |= SWP_NOMOVE;
  796. }
  797. SetSSWindowPos( uFlags );
  798. // ! remember not to call the client's ReshapeFunc here, as SetAspectRatio
  799. // may be called by the client in response to a window resize, resulting in
  800. // an infinite loop
  801. //mf: but if there is no size change (above) we return, avoiding the
  802. // infinite loop
  803. if( !hwnd )
  804. // Need to call Reshape, since win32 system won't send WM_SIZE. Need
  805. // to fix to avoid possible infinite loops
  806. Reshape();
  807. return TRUE;
  808. }
  809. /**************************************************************************\
  810. * CalcNextWindowPos
  811. *
  812. * Calculate the next position for a moving window, using the pMotion data.
  813. * If the new position would cause the window to bounce off the
  814. * edge of its parent, return TRUE.
  815. *
  816. \**************************************************************************/
  817. BOOL
  818. SSW::CalcNextWindowPos()
  819. {
  820. POINT2D *fpos = &pMotion->pos;
  821. IPOINT2D *ipos = &pos;
  822. POINT2D *posInc = &pMotion->posInc;
  823. POINT2D *posIncV = &pMotion->posIncVary;
  824. POINT2D *posIncCur = &pMotion->posIncCur;
  825. BOOL bounce = FALSE;
  826. if( !psswParent )
  827. return FALSE;
  828. // Compute the next window position.
  829. fpos->x += posIncCur->x;
  830. fpos->y += posIncCur->y;
  831. ipos->x = (int) fpos->x;
  832. ipos->y = (int) fpos->y;
  833. if ( (ipos->x + size.width) > psswParent->size.width) {
  834. // Right hit
  835. ipos->x = psswParent->size.width - size.width;
  836. fpos->x = (float) ipos->x;
  837. posIncCur->x =
  838. - ss_fRand( posInc->x - posIncV->x, posInc->x + posIncV->x );
  839. if( posIncCur->x > -0.5f ) posIncCur->x = -0.5f;
  840. bounce = TRUE;
  841. } else if (ipos->x < 0) {
  842. // Left hit
  843. ipos->x = 0;
  844. fpos->x = 0.0f;
  845. posIncCur->x =
  846. ss_fRand( posInc->x - posIncV->x, posInc->x + posIncV->x );
  847. if( posIncCur->x < 0.5f ) posIncCur->x = 0.5f;
  848. bounce = TRUE;
  849. }
  850. if ( (ipos->y + size.height) > psswParent->size.height) {
  851. // Bottom hit
  852. ipos->y = psswParent->size.height - size.height;
  853. fpos->y = (float) (ipos->y);
  854. posIncCur->y =
  855. - ss_fRand( posInc->y - posIncV->y, posInc->y + posIncV->y );
  856. if( posIncCur->y > -0.5f ) posIncCur->y = -0.5f;
  857. bounce = TRUE;
  858. } else if (ipos->y < 0) {
  859. // Top hit
  860. ipos->y = 0;
  861. fpos->y = 0.0f;
  862. posIncCur->y =
  863. ss_fRand( posInc->y - posIncV->y, posInc->y + posIncV->y );
  864. if( posIncCur->y < 0.5f ) posIncCur->y = 0.5f;
  865. bounce = TRUE;
  866. }
  867. return bounce;
  868. }
  869. /**************************************************************************\
  870. * MoveSSWindow
  871. *
  872. * This is the function that moves the OpenGL window around, causing it to
  873. * bounce around. Each time the window is moved, the contents of the
  874. * window are updated from the hidden (or back) buffer by SwapBuffers().
  875. *
  876. * The bRedrawBg flag determines whether the area that was covered by the old
  877. * position should be updated by the parent window.
  878. *
  879. \**************************************************************************/
  880. void
  881. SSW::MoveSSWindow( BOOL bRedrawBg )
  882. {
  883. BOOL bounce;
  884. int flags = SWP_NOSIZE;
  885. // Synchronize with OpenGL. Flush OpenGL commands and wait for completion.
  886. glFinish();
  887. // Move the window
  888. bounce = CalcNextWindowPos();
  889. if( bounce && FloaterBounceFunc )
  890. // The window bounced off one of the sides
  891. // ! This function should *not* be used for rendering - for
  892. // informational purposes only (.e.g. changing the spin of a
  893. // rotating object).
  894. (*FloaterBounceFunc)( DataPtr );
  895. if( !bRedrawBg )
  896. flags |= SWP_NOREDRAW;
  897. SetSSWindowPos( flags );
  898. }
  899. /**************************************************************************\
  900. * UpdateWindow
  901. *
  902. * Update the window
  903. *
  904. * Ccurrently this assumes all windows are being animated (i.e. not showing
  905. * a static image)
  906. *
  907. * Things *must* happen in the order defined here, so they work on generic as
  908. * well as hardware implementations.
  909. * Note: Move must happen after SwapBuf, and will cause some encroaching on
  910. * the current display, as the parent window repaints after the move. Therefore
  911. * apps must take care to leave an empty border around their rendered image,
  912. * equal to the maximum window move delta.
  913. *
  914. \**************************************************************************/
  915. void
  916. SSW::UpdateWindow()
  917. {
  918. // update any children first
  919. PSSW pssw = psswChildren;
  920. while( pssw ) {
  921. pssw->UpdateWindow();
  922. pssw = pssw->psswSibling;
  923. }
  924. //mf: semi-kluge
  925. // If this window is a subWindow in a non-generic implementation, the
  926. // background of the parent may be invalid (this may eventually be
  927. // useful for regular windows, which is why we don't && !hwnd)
  928. if( psswParent &&
  929. psswParent->bValidateBg &&
  930. pGLc &&
  931. !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) )
  932. {
  933. // Clear the entire parent window
  934. // mf: I think this is only needed for double-buffered schemes, since
  935. // the windowing system should repaint the front buffer in this case.
  936. glDisable( GL_SCISSOR_TEST );
  937. glClear( GL_COLOR_BUFFER_BIT );
  938. glEnable( GL_SCISSOR_TEST );
  939. psswParent->bValidateBg = FALSE;
  940. }
  941. if( !UpdateFunc )
  942. return;
  943. // bDoubleBuf and pStretch should be mutually exclusive...
  944. if( bDoubleBuf || pStretch ) {
  945. UpdateDoubleBufWin();
  946. } else {
  947. //mf: ? where's the clearing here ? (true, no one uses this path...)
  948. if( pMotion )
  949. MoveSSWindow( TRUE );
  950. (*UpdateFunc)( DataPtr );
  951. }
  952. }
  953. /**************************************************************************\
  954. * UpdateDoubleBufWin
  955. *
  956. * This is used when moving a double buffered window around. It will
  957. * work for all configurations.
  958. *
  959. \**************************************************************************/
  960. void
  961. SSW::UpdateDoubleBufWin()
  962. {
  963. if( !hwnd ) {
  964. UpdateDoubleBufSubWin();
  965. return;
  966. }
  967. RECT updateRect;
  968. // Move the window
  969. if( pMotion ) {
  970. // Save child update rect before move
  971. GetSSWindowRect( &updateRect );
  972. // Move window, without repainting exposed area
  973. MoveSSWindow( FALSE );
  974. }
  975. // Update the back buffer
  976. (*UpdateFunc)( DataPtr );
  977. if( pMotion ) {
  978. // (pMotion will be NULL if this window has no parent)
  979. if( hwnd ) {
  980. // Paint the exposed area with bg brush (the current image will
  981. // be partially erased momentarily, until the SwapBuffers() call
  982. // comes through)
  983. // (This rect should be clipped to our new window position...)
  984. DrawGdiRect( psswParent->hdc, gpss->hbrBg, &updateRect );
  985. } else {
  986. //mf: currently this path not possible, since if !hwnd, we use one of the
  987. // UpdateDoubleBufSubWin* functions
  988. SS_WARNING( "SSW::UpdateDoubleBufWin: no hwnd\n" );
  989. // sub-window case : need to do our own clipping
  990. RECT newRect;
  991. GetSSWindowRect( &newRect );
  992. DrawGdiDeltaRect( psswParent->hdc, gpss->hbrBg, &updateRect, &newRect );
  993. }
  994. }
  995. // Swap to the new window position
  996. SwapSSBuffers();
  997. }
  998. /**************************************************************************\
  999. * UpdateDoubleBufSubWin
  1000. *
  1001. * Used for generic double buffered gl sub-windows.
  1002. *
  1003. \**************************************************************************/
  1004. void
  1005. SSW::UpdateDoubleBufSubWin()
  1006. {
  1007. GLRECT curRect, newRect;
  1008. // AddSwapHintRect for current position
  1009. glAddSwapHintRect( pos.x, GLPosY(), size.width, size.height );
  1010. if( pMotion ) {
  1011. // Save current rect
  1012. curRect.x = pos.x;
  1013. curRect.y = GLPosY();
  1014. curRect.width = size.width;
  1015. curRect.height = size.height;
  1016. // Move window, without repainting exposed area
  1017. MoveSSWindow( FALSE );
  1018. // Get new rect
  1019. newRect.x = pos.x;
  1020. newRect.y = GLPosY();
  1021. newRect.width = size.width;
  1022. newRect.height = size.height;
  1023. DrawGLDeltaRect( &curRect, &newRect );
  1024. // Have to consider previous rect for ICD or MCD
  1025. if( !(pGLc->pfFlags & SS_GENERIC_UNACCELERATED_BIT) ) {
  1026. DrawGLDeltaRect( &lastRect, &newRect );
  1027. lastRect = curRect;
  1028. }
  1029. // Reset scissor to new rect (this *was* set by MoveSSWindow, but
  1030. // DrawGLDeltaRect sets scissor to do its clearing
  1031. glScissor( newRect.x, newRect.y, newRect.width, newRect.height );
  1032. }
  1033. // Update the back buffer
  1034. (*UpdateFunc)( DataPtr );
  1035. // Swap to the new window position
  1036. SwapSSBuffers();
  1037. }
  1038. /******************************Public*Routine******************************\
  1039. * RandomWindowPos
  1040. *
  1041. * Sets a new random window position and motion
  1042. *
  1043. \**************************************************************************/
  1044. void
  1045. SSW::RandomWindowPos()
  1046. {
  1047. if( psswParent ) {
  1048. if( !hwnd ) {
  1049. // sub-window : manually clear old window rect
  1050. if( bDoubleBuf ) {
  1051. glClear( GL_COLOR_BUFFER_BIT );
  1052. } else {
  1053. RECT oldRect;
  1054. GetSSWindowRect( &oldRect );
  1055. DrawGdiRect( psswParent->hdc, gpss->hbrBg, &oldRect );
  1056. }
  1057. }
  1058. // Calc and set new position
  1059. pos.x = ss_iRand2( 0, (psswParent->size.width - size.width) );
  1060. pos.y = ss_iRand2( 0, (psswParent->size.height - size.height) );
  1061. SetSSWindowPos( SWP_NOSIZE );
  1062. // Reset motion
  1063. if( pMotion )
  1064. ResetMotion();
  1065. }
  1066. }
  1067. /**************************************************************************\
  1068. * ResetMotion
  1069. *
  1070. * Calculate a random position and motion vector for the floater window
  1071. * Note that a floating point position is maintained for DDA window movement
  1072. *
  1073. \**************************************************************************/
  1074. void
  1075. SSW::ResetMotion()
  1076. {
  1077. if( !psswParent || !pMotion )
  1078. // Only child windows can be reset
  1079. return;
  1080. // Set floating point pos also, for DDA
  1081. pMotion->pos.x = (float) pos.x;
  1082. pMotion->pos.y = (float) pos.y;
  1083. // also reset the window motion directions
  1084. if( ss_iRand(2) ) // 0 or 1
  1085. pMotion->posIncCur.x = - pMotion->posIncCur.x;
  1086. if( ss_iRand(2) )
  1087. pMotion->posIncCur.y = - pMotion->posIncCur.y;
  1088. }
  1089. /**************************************************************************\
  1090. * ValidateChildSize
  1091. *
  1092. * Make sure it's not bigger than its parent
  1093. *
  1094. \**************************************************************************/
  1095. void
  1096. SSW::ValidateChildSize()
  1097. {
  1098. if( !psswParent )
  1099. return;
  1100. SS_CLAMP_TO_RANGE2( size.width, 0, psswParent->size.width );
  1101. SS_CLAMP_TO_RANGE2( size.height, 0, psswParent->size.height );
  1102. }
  1103. /**************************************************************************\
  1104. * bValidateChildPos
  1105. *
  1106. * Make sure that with the current window position, none of the floating
  1107. * window extends beyond the parent window.
  1108. *
  1109. \**************************************************************************/
  1110. BOOL
  1111. SSW::bValidateChildPos()
  1112. {
  1113. BOOL bRet = FALSE;
  1114. if( !psswParent )
  1115. return FALSE;
  1116. if ( (pos.x + size.width) > psswParent->size.width) {
  1117. pos.x = psswParent->size.width - size.width;
  1118. bRet = TRUE;
  1119. }
  1120. if ( (pos.y + size.height) > psswParent->size.height) {
  1121. pos.y = psswParent->size.height - size.height;
  1122. bRet = TRUE;
  1123. }
  1124. return bRet;
  1125. }
  1126. /**************************************************************************\
  1127. * GetSSWindowRect
  1128. *
  1129. * Return window position and size in supplied RECT structure
  1130. *
  1131. * mf: this rect is relative to the parent
  1132. \**************************************************************************/
  1133. void
  1134. SSW::GetSSWindowRect( LPRECT lpRect )
  1135. {
  1136. lpRect->left = pos.x;
  1137. lpRect->top = pos.y;
  1138. lpRect->right = pos.x + size.width;
  1139. lpRect->bottom = pos.y + size.height;
  1140. }
  1141. /**************************************************************************\
  1142. * GLPosY
  1143. *
  1144. * Return y-coord of window position in GL coordinates (a win32 window position
  1145. * (starts from top left, while GL starts from bottom left)
  1146. *
  1147. \**************************************************************************/
  1148. int
  1149. SSW::GLPosY()
  1150. {
  1151. if( !psswParent )
  1152. return 0;
  1153. return psswParent->size.height - size.height - pos.y;
  1154. }
  1155. /**************************************************************************\
  1156. * SwapStretchBuffers
  1157. *
  1158. * Swaps from the stretch buffer to the GL window, using StretchBlt
  1159. *
  1160. \**************************************************************************/
  1161. void
  1162. SSW::SwapStretchBuffers()
  1163. {
  1164. SS_BITMAP *pssbm = &pStretch->ssbm;
  1165. if( (size.width == pssbm->size.width) &&
  1166. (size.height == pssbm->size.height) ) // buffers same size
  1167. {
  1168. BitBlt(hdc, 0, 0, size.width, size.height,
  1169. pssbm->hdc, 0, 0, SRCCOPY);
  1170. }
  1171. else
  1172. {
  1173. StretchBlt(hdc, 0, 0, size.width, size.height,
  1174. pssbm->hdc, 0, 0, pssbm->size.width, pssbm->size.height,
  1175. SRCCOPY);
  1176. }
  1177. GdiFlush();
  1178. }
  1179. /**************************************************************************\
  1180. * SwapBuffers
  1181. *
  1182. * Wrapper for SwapBuffers / SwapStretchBuffers
  1183. *
  1184. \**************************************************************************/
  1185. void
  1186. SSW::SwapSSBuffers()
  1187. {
  1188. if( pStretch )
  1189. SwapStretchBuffers();
  1190. else if( bDoubleBuf ) {
  1191. SwapBuffers( hdc );
  1192. }
  1193. }
  1194. /**************************************************************************\
  1195. * Reshape
  1196. *
  1197. * Reshape wrapper
  1198. * Sends reshape msg to screen saver
  1199. * This is the size of the surface that gl renders onto, which can be a bitmap.
  1200. *
  1201. \**************************************************************************/
  1202. void
  1203. SSW::Reshape()
  1204. {
  1205. // Point to size of window, or bitmap if it has one
  1206. ISIZE *pSize = &size;
  1207. if( pStretch )
  1208. pSize = &pStretch->ssbm.size;
  1209. // If the window has an hrc, set default viewport
  1210. if( hrc ) {
  1211. if( hwnd )
  1212. glViewport( 0, 0, pSize->width, pSize->height );
  1213. else if ( psswParent ) {
  1214. // sub-window (only 1 level of sub-windowing supported)
  1215. //mf: klugey ? - should take into account non-GL and single buffer...
  1216. #if 1
  1217. // clear entire window to black
  1218. glDisable( GL_SCISSOR_TEST );
  1219. glClear( GL_COLOR_BUFFER_BIT );
  1220. glEnable( GL_SCISSOR_TEST );
  1221. #endif
  1222. // Convert win32 y-coord to GL
  1223. glViewport( pos.x, GLPosY(), pSize->width, pSize->height );
  1224. }
  1225. }
  1226. if( ReshapeFunc ) {
  1227. (*ReshapeFunc)( pSize->width, pSize->height, DataPtr );
  1228. }
  1229. }
  1230. /******************************Public*Routine******************************\
  1231. * GdiClear
  1232. *
  1233. * Clears window using Gdi FillRect
  1234. \**************************************************************************/
  1235. void
  1236. SSW::GdiClear()
  1237. {
  1238. if( !hdc )
  1239. return;
  1240. RECT rect;
  1241. //mf: this should use GetClientRect
  1242. GetSSWindowRect( &rect );
  1243. FillRect( hdc, &rect, gpss->hbrBg );
  1244. GdiFlush();
  1245. }
  1246. /******************************Public*Routine******************************\
  1247. * MyAddSwapHintRect
  1248. *
  1249. \**************************************************************************/
  1250. static void _stdcall
  1251. MyAddSwapHintRect(GLint xs, GLint ys, GLint xe, GLint ye)
  1252. {
  1253. return;
  1254. }
  1255. /******************************Public*Routine******************************\
  1256. * QueryAddSwapHintRectWIN
  1257. *
  1258. \**************************************************************************/
  1259. static void
  1260. ss_QueryAddSwapHintRect()
  1261. {
  1262. glAddSwapHintRect = (PFNGLADDSWAPHINTRECTWINPROC)
  1263. wglGetProcAddress("glAddSwapHintRectWIN");
  1264. if (glAddSwapHintRect == NULL) {
  1265. glAddSwapHintRect = MyAddSwapHintRect;
  1266. }
  1267. }
  1268. /******************************Public*Routine******************************\
  1269. * DrawGdiDeltaRect
  1270. *
  1271. * Draw the exposed area by transition from rect1 to rect2
  1272. \**************************************************************************/
  1273. static void
  1274. DrawGdiDeltaRect( HDC hdc, HBRUSH hbr, RECT *pRect1, RECT *pRect2 )
  1275. {
  1276. if( (pRect1 == NULL) || (pRect2 == NULL) ) {
  1277. SS_WARNING( "DrawGdiDeltaRect : one or both rects are NULL\n" );
  1278. return;
  1279. }
  1280. // Draw 2 rects
  1281. RECT rect;
  1282. // Rect exposed in x-direction:
  1283. rect.top = pRect1->top;
  1284. rect.bottom = pRect1->bottom;
  1285. if( pRect2->left > pRect1->left ) {
  1286. // moving right
  1287. rect.left = pRect1->left;
  1288. rect.right = pRect2->left;
  1289. } else {
  1290. // moving left
  1291. rect.left = pRect2->right;
  1292. rect.right = pRect1->right;
  1293. }
  1294. FillRect( hdc, &rect, hbr );
  1295. // Rect exposed in y-direction:
  1296. rect.left = pRect1->left;
  1297. rect.right = pRect1->right;
  1298. if( pRect2->bottom > pRect1->bottom ) {
  1299. // moving down
  1300. rect.top = pRect1->top;
  1301. rect.bottom = pRect2->top;
  1302. } else {
  1303. // moving up
  1304. rect.top = pRect2->bottom;
  1305. rect.bottom = pRect1->bottom;
  1306. }
  1307. FillRect( hdc, &rect, hbr );
  1308. GdiFlush();
  1309. }
  1310. /******************************Public*Routine******************************\
  1311. * DrawGLDeltaRect
  1312. *
  1313. * Draw the exposed area by transition from rect1 to rect2
  1314. \**************************************************************************/
  1315. static void
  1316. DrawGLDeltaRect( GLRECT *pRect1, GLRECT *pRect2 )
  1317. {
  1318. if( (pRect1 == NULL) || (pRect2 == NULL) ) {
  1319. SS_WARNING( "DrawGLDeltaRect : one or both rects are NULL\n" );
  1320. return;
  1321. }
  1322. // Draw 2 rects :
  1323. //mf: !!! this assumes rect1 and rect2 have same dimensions !
  1324. GLRECT rect;
  1325. // Rect exposed in x-direction:
  1326. rect.height = pRect1->height;
  1327. rect.y = pRect1->y;
  1328. if( pRect2->x > pRect1->x ) {
  1329. // moving right
  1330. rect.width = pRect2->x - pRect1->x;
  1331. rect.x = pRect1->x;
  1332. } else {
  1333. // moving left
  1334. rect.width = pRect1->x - pRect2->x;
  1335. rect.x = pRect2->x + pRect2->width;
  1336. }
  1337. glScissor( rect.x, rect.y, rect.width, rect.height );
  1338. glClear( GL_COLOR_BUFFER_BIT );
  1339. // Rect exposed in y-direction:
  1340. rect.width = pRect1->width;
  1341. rect.x = pRect1->x;
  1342. if( pRect2->y > pRect1->y ) {
  1343. // moving up
  1344. rect.height = pRect2->y - pRect1->y;
  1345. rect.y = pRect1->y;
  1346. } else {
  1347. // moving down
  1348. rect.height = pRect1->y - pRect2->y;
  1349. rect.y = pRect2->y + pRect2->height;
  1350. }
  1351. glScissor( rect.x, rect.y, rect.width, rect.height );
  1352. glClear( GL_COLOR_BUFFER_BIT );
  1353. }