Leaked source code of windows server 2003
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.

10082 lines
315 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: sprite.cxx
  3. *
  4. * Contains all the drawing code for handling GDI sprites.
  5. *
  6. * Created: 16-Sep-1997
  7. * Author: J. Andrew Goossen [andrewgo]
  8. *
  9. * Copyright (c) 1997-1999 Microsoft Corporation
  10. *
  11. \**************************************************************************/
  12. #include "precomp.hxx"
  13. // Notes
  14. //
  15. // - EngAlphaBlend always calls 32BitfieldsToBGRA with identity pxlo
  16. // - pSprite->rclSrc no longer needed
  17. // - Fix vProfile for smart heap management
  18. // Global variable that defines a (0, 0) offset:
  19. POINTL gptlZero;
  20. POINTL gptl00;
  21. // Handy forward declarations:
  22. VOID vSpComputeUnlockedRegion(SPRITESTATE*);
  23. VOID vSpCheckForWndobjOverlap(SPRITESTATE*, RECTL*, RECTL*);
  24. /******************************Public*Routine******************************\
  25. * VOID vSpDirectDriverAccess
  26. *
  27. * If 'bEnable' is TRUE, this routine undoes any sprite modifications to
  28. * the surface, in order to allow us to call the driver from within the
  29. * sprite code.
  30. *
  31. * If 'bEnable' is FALSE, this routine redoes any sprite modifications to
  32. * the surface that are needed for any drawing calls outside of this file,
  33. * in order to be redirected through the sprite code as appropriate.
  34. *
  35. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  36. * Wrote it.
  37. \**************************************************************************/
  38. VOID vSpDirectDriverAccess(
  39. SPRITESTATE* pState,
  40. BOOL bEnable)
  41. {
  42. PDEVOBJ po(pState->hdev);
  43. po.vAssertDevLock();
  44. if (bEnable)
  45. {
  46. SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen)->
  47. flags(pState->flOriginalSurfFlags);
  48. SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen)->
  49. iType(pState->iOriginalType);
  50. pState->bInsideDriverCall = TRUE;
  51. }
  52. else
  53. {
  54. SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen)->
  55. flags(pState->flSpriteSurfFlags);
  56. SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen)->
  57. iType(pState->iSpriteType);
  58. pState->bInsideDriverCall = FALSE;
  59. }
  60. }
  61. #if DEBUG_SPRITES
  62. /******************************Debug*Routine*******************************\
  63. * VOID vSpValidateVisibleSprites
  64. *
  65. * Walk visible spritelist and validates cVisible count equals number of
  66. * sprites in pListVisible.
  67. *
  68. * 08-May-2001 -by- Jason Hartman [jasonha]
  69. * Wrote it.
  70. \**************************************************************************/
  71. void vSpValidateVisibleSprites(
  72. SPRITESTATE *pState
  73. )
  74. {
  75. ULONG cVisible;
  76. SPRITE *pSprite;
  77. cVisible = pState->cVisible;
  78. for (pSprite = pState->pListVisible;
  79. pSprite != NULL;
  80. pSprite = pSprite->pNextVisible)
  81. {
  82. ASSERTGDI(cVisible != 0, "Invalid visible sprite list: list is longer than cVisible.\n");
  83. cVisible--;
  84. ASSERTGDI(pSprite->fl & SPRITE_FLAG_VISIBLE, "Invalid sprite visible state: invisible sprite in visible list.\n");
  85. }
  86. ASSERTGDI(cVisible == 0, "Invalid visible sprite list: list is missing a sprite or more.\n");
  87. cVisible = pState->cVisible;
  88. for (pSprite = pState->pListZ;
  89. pSprite != NULL;
  90. pSprite = pSprite->pNextZ)
  91. {
  92. if (pSprite->fl & SPRITE_FLAG_VISIBLE)
  93. {
  94. ASSERTGDI(cVisible != 0, "Invalid visible sprite count: cVisible is too small.\n");
  95. cVisible--;
  96. }
  97. }
  98. ASSERTGDI(cVisible == 0, "Invalid visible sprite count: cVisible is too big.\n");
  99. }
  100. #endif
  101. /*********************************Class************************************\
  102. * class SPRITELOCK
  103. *
  104. * This class is responsible for reseting whatever sprite state is
  105. * necessary so that we can call the driver directly, bypassing any sprite
  106. * code.
  107. *
  108. * Must be called with the DEVLOCK already held, because we're
  109. * messing with the screen surface.
  110. *
  111. \***************************************************************************/
  112. SPRITELOCK::SPRITELOCK(PDEVOBJ& po)
  113. {
  114. pState = po.pSpriteState();
  115. po.vAssertDevLock();
  116. bWasAlreadyInsideDriverCall = pState->bInsideDriverCall;
  117. if (!bWasAlreadyInsideDriverCall)
  118. {
  119. vSpDirectDriverAccess(pState, TRUE);
  120. }
  121. #if DEBUG_SPRITES
  122. vSpValidateVisibleSprites(pState);
  123. #endif
  124. }
  125. SPRITELOCK::~SPRITELOCK()
  126. {
  127. #if DEBUG_SPRITES
  128. vSpValidateVisibleSprites(pState);
  129. #endif
  130. if (!bWasAlreadyInsideDriverCall)
  131. {
  132. vSpDirectDriverAccess(pState, FALSE);
  133. }
  134. }
  135. /******************************Public*Routine******************************\
  136. * VOID psoSpCreateSurface
  137. *
  138. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  139. * Wrote it.
  140. \**************************************************************************/
  141. SURFOBJ* psoSpCreateSurface(
  142. SPRITESTATE* pState,
  143. ULONG iBitmapFormat, // If zero, use same format as display
  144. LONG cx,
  145. LONG cy,
  146. BOOL bWantSystemMemory) // TRUE if must be system memory, FALSE
  147. // if can be in video memory
  148. {
  149. HSURF hsurf;
  150. SIZEL sizl;
  151. SURFOBJ* psoScreen;
  152. SURFOBJ* psoRet;
  153. SURFACE* psurf;
  154. PDEVOBJ po(pState->hdev);
  155. psoRet = NULL;
  156. sizl.cx = cx;
  157. sizl.cy = cy;
  158. psoScreen = pState->psoScreen;
  159. if (iBitmapFormat == 0)
  160. {
  161. iBitmapFormat = psoScreen->iBitmapFormat;
  162. }
  163. hsurf = 0;
  164. if ((!bWantSystemMemory) &&
  165. (PPFNVALID(po, CreateDeviceBitmap)) &&
  166. (iBitmapFormat == psoScreen->iBitmapFormat))
  167. {
  168. hsurf = (HSURF) (*PPFNDRV(po, CreateDeviceBitmap))
  169. (psoScreen->dhpdev,
  170. sizl,
  171. iBitmapFormat);
  172. }
  173. if (hsurf == 0)
  174. {
  175. hsurf = (HSURF) EngCreateBitmap(sizl,
  176. 0,
  177. iBitmapFormat,
  178. BMF_TOPDOWN,
  179. NULL);
  180. }
  181. if (hsurf != 0)
  182. {
  183. psoRet = EngLockSurface(hsurf);
  184. ASSERTGDI(psoRet != NULL, "How could lock possibly fail?");
  185. // Mark the surface, so that it can be special-cased by
  186. // the dynamic mode change code:
  187. psurf = SURFOBJ_TO_SURFACE_NOT_NULL(psoRet);
  188. psurf->hdev(pState->hdev);
  189. }
  190. return(psoRet);
  191. }
  192. /******************************Public*Routine******************************\
  193. * VOID vSpDeleteSurface
  194. *
  195. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  196. * Wrote it.
  197. \**************************************************************************/
  198. VOID vSpDeleteSurface(
  199. SURFOBJ* pso)
  200. {
  201. HSURF hsurf;
  202. // Note that EngDeleteSurface handles calling DrvDeleteDeviceBitmap
  203. // if it's a device format bitmap:
  204. if (pso != NULL)
  205. {
  206. hsurf = pso->hsurf;
  207. EngUnlockSurface(pso);
  208. EngDeleteSurface(hsurf);
  209. }
  210. }
  211. /**********************************Macros**********************************\
  212. * OFFSET_POINTL, OFFSET_RECTL
  213. *
  214. * These little macros offset simple structures using a copy on the stack.
  215. *
  216. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  217. * Wrote it.
  218. \**************************************************************************/
  219. #define OFFSET_POINTL(pptl, xOff, yOff) \
  220. POINTL ptlCopyOf##pptl; \
  221. POINTL* pptlOriginal##pptl; \
  222. if (pptl != NULL) \
  223. { \
  224. ptlCopyOf##pptl.x = xOff + pptl->x; \
  225. ptlCopyOf##pptl.y = yOff + pptl->y; \
  226. pptlOriginal##pptl = pptl; \
  227. pptl = &ptlCopyOf##pptl; \
  228. }
  229. #define OFFSET_RECTL(prcl, xOff, yOff) \
  230. RECTL rclCopyOf##prcl; \
  231. if (prcl != NULL) \
  232. { \
  233. rclCopyOf##prcl.left = xOff + prcl->left; \
  234. rclCopyOf##prcl.right = xOff + prcl->right; \
  235. rclCopyOf##prcl.top = yOff + prcl->top; \
  236. rclCopyOf##prcl.bottom = yOff + prcl->bottom; \
  237. prcl = &rclCopyOf##prcl; \
  238. }
  239. #define OFFSET_POINTL_NOT_NULL(pptl, xOff, yOff) \
  240. POINTL ptlCopyOf##pptl; \
  241. ptlCopyOf##pptl.x = xOff + pptl->x; \
  242. ptlCopyOf##pptl.y = yOff + pptl->y; \
  243. pptl = &ptlCopyOf##pptl;
  244. #define OFFSET_RECTL_NOT_NULL(prcl, xOff, yOff) \
  245. RECTL rclCopyOf##prcl; \
  246. rclCopyOf##prcl.left = xOff + prcl->left; \
  247. rclCopyOf##prcl.right = xOff + prcl->right; \
  248. rclCopyOf##prcl.top = yOff + prcl->top; \
  249. rclCopyOf##prcl.bottom = yOff + prcl->bottom; \
  250. prcl = &rclCopyOf##prcl;
  251. // The following little macro is here to catch any Drv or Eng functions
  252. // that illegaly modify the value of 'pptlBrush'. If you hit this assert,
  253. // it means that the function we just called is a culprit.
  254. #define ASSERT_BRUSH_ORIGIN(pptl, xOff, yOff) \
  255. ASSERTGDI((pptl == NULL) || \
  256. ((ptlCopyOf##pptl.x == xOff + pptlOriginal##pptl->x) && \
  257. (ptlCopyOf##pptl.y == yOff + pptlOriginal##pptl->y)), \
  258. "Called function modified pptlBrush");
  259. /******************************Public*Routine******************************\
  260. * VOID CLIPOBJ_vOffset
  261. *
  262. * These are little in-line routines to handle offseting of complex
  263. * structures that must remain in-place.
  264. *
  265. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  266. * Wrote it.
  267. \**************************************************************************/
  268. VOID FASTCALL CLIPOBJ_vOffset(
  269. CLIPOBJ* pco,
  270. LONG x,
  271. LONG y)
  272. {
  273. POINTL ptlOffset;
  274. if (pco != NULL)
  275. {
  276. if ((x != 0) || (y != 0))
  277. {
  278. pco->rclBounds.left += x;
  279. pco->rclBounds.right += x;
  280. pco->rclBounds.top += y;
  281. pco->rclBounds.bottom += y;
  282. if (pco->iDComplexity != DC_TRIVIAL)
  283. {
  284. ptlOffset.x = x;
  285. ptlOffset.y = y;
  286. ((XCLIPOBJ*) pco)->bOffset(&ptlOffset);
  287. }
  288. }
  289. }
  290. }
  291. /******************************Public*Routine******************************\
  292. * VOID STROBJ_vOffset
  293. *
  294. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  295. * Wrote it.
  296. \**************************************************************************/
  297. VOID FASTCALL STROBJ_vOffset(
  298. STROBJ* pstro,
  299. LONG x,
  300. LONG y)
  301. {
  302. GLYPHPOS* pgp;
  303. ULONG cGlyphs;
  304. if ((x != 0) || (y != 0))
  305. {
  306. pstro->rclBkGround.left += x;
  307. pstro->rclBkGround.right += x;
  308. pstro->rclBkGround.top += y;
  309. pstro->rclBkGround.bottom += y;
  310. // We are just offsetting positions, they are always computed,
  311. // unless;
  312. //
  313. // a) this is a fixed pitch font (ulCharInc != 0), in which case only
  314. // first position in the batch is set.
  315. //
  316. // b) we are dealing with linked fonts.
  317. //
  318. // bEnum is just putting bits in the cache, that is independent
  319. // of computing positions.
  320. if (((ESTROBJ*)pstro)->flTO & TO_HIGHRESTEXT)
  321. {
  322. x <<= 4;
  323. y <<= 4;
  324. }
  325. pgp = ((ESTROBJ*)pstro)->pgpos;
  326. if(((ESTROBJ*)pstro)->flTO & (TO_PARTITION_INIT|TO_SYS_PARTITION))
  327. {
  328. LONG *plFont;
  329. plFont = ((ESTROBJ*)pstro)->plPartition;
  330. for (cGlyphs = pstro->cGlyphs ; cGlyphs != 0; pgp++, plFont++)
  331. {
  332. // only offset the glyphs that correspond to the current font:
  333. if (*plFont == ((ESTROBJ*)pstro)->lCurrentFont)
  334. {
  335. cGlyphs--;
  336. pgp->ptl.x += x;
  337. pgp->ptl.y += y;
  338. }
  339. }
  340. }
  341. else
  342. {
  343. if (!pstro->ulCharInc)
  344. {
  345. cGlyphs = pstro->cGlyphs;
  346. for (; cGlyphs != 0; cGlyphs--, pgp++)
  347. {
  348. pgp->ptl.x += x;
  349. pgp->ptl.y += y;
  350. }
  351. }
  352. else
  353. {
  354. // fixed pitch, only fix the first position, the rest will be
  355. // computed during bEnum phase if necessary
  356. pgp->ptl.x += x;
  357. pgp->ptl.y += y;
  358. }
  359. }
  360. }
  361. }
  362. /******************************Public*Routine******************************\
  363. * VOID PATHOBJ_vOffset
  364. *
  365. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  366. * Wrote it.
  367. \**************************************************************************/
  368. VOID FASTCALL PATHOBJ_vOffset(
  369. PATHOBJ* ppo,
  370. LONG x,
  371. LONG y)
  372. {
  373. BOOL bMore;
  374. PATHDATA pd;
  375. POINTFIX* pptfx;
  376. ULONG cptfx;
  377. if ((x != 0) || (y != 0))
  378. {
  379. EPOINTL eptl(x, y);
  380. ((EPATHOBJ*) ppo)->vOffset(eptl);
  381. }
  382. }
  383. /*********************************Macro************************************\
  384. * macro OFFBITBLT
  385. *
  386. * This handy little macro invokes OffBitBlt to call either EngBitBlt or
  387. * DrvBitBlt, depending on whether the destination surface is owned by
  388. * the device.
  389. \**************************************************************************/
  390. #define OFFBITBLT(pOffDst_, psoDst_, pOffSrc_, psoSrc_, psoMsk_, pco_, \
  391. pxlo_, prclDst_, pptlSrc_, pptlMsk_, pbo_, pptlBrush_,\
  392. rop4_) \
  393. OffBitBlt(PPFNDIRECT(psoDst_, BitBlt), \
  394. pOffDst_, psoDst_, pOffSrc_, psoSrc_, psoMsk_, pco_, \
  395. pxlo_, prclDst_, pptlSrc_, pptlMsk_, pbo_, pptlBrush_, rop4_)
  396. /*********************************Macro************************************\
  397. * macro OFFCOPYBITS
  398. *
  399. * This handy little macro invokes OffCopyBits to call either EngCopyBits or
  400. * DrvCopyBits, depending on whether either of the surfaces are owned by
  401. * the device.
  402. \**************************************************************************/
  403. #define OFFCOPYBITS(pOffDst_, psoDst_, pOffSrc_, psoSrc_, pco_, pxlo_, \
  404. prclDst_, pptlSrc_) \
  405. OffCopyBits(((!(SURFOBJ_TO_SURFACE_NOT_NULL((psoDst_))->flags() & HOOK_CopyBits)\
  406. && (psoSrc_->hdev)) \
  407. ? PPFNDIRECT(psoSrc_, CopyBits) \
  408. : PPFNDIRECT(psoDst_, CopyBits)), \
  409. pOffDst_, psoDst_, pOffSrc_, psoSrc_, pco_, pxlo_, prclDst_, \
  410. pptlSrc_)
  411. /******************************Public*Routine******************************\
  412. * BOOL Off*
  413. *
  414. * These routines handle the offseting of coordinates given to the driver,
  415. * for the purposes of multi-monitor and sprite support. Each of these
  416. * routines correspond to a DDI drawing call, and offsets all drawing
  417. * coordinates by the 'xOffset' and 'yOffset' values in the corresponding
  418. * SURFOBJ.
  419. *
  420. * Some complex DDI data-structures such as PATHOBJs and TEXTOBJs must be
  421. * modified in-place; they are always reset to their original values before
  422. * returning.
  423. *
  424. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  425. * Wrote it.
  426. \**************************************************************************/
  427. /******************************Public*Routine******************************\
  428. * BOOL OffStrokePath
  429. *
  430. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  431. * Wrote it.
  432. \**************************************************************************/
  433. BOOL OffStrokePath(
  434. PFN_DrvStrokePath pfnStrokePath,
  435. POINTL* pOffset,
  436. SURFOBJ* pso,
  437. PATHOBJ* ppo,
  438. CLIPOBJ* pco,
  439. XFORMOBJ* pxo,
  440. BRUSHOBJ* pbo,
  441. POINTL* pptlBrush,
  442. LINEATTRS* pla,
  443. MIX mix)
  444. {
  445. LONG x;
  446. LONG y;
  447. x = pOffset->x;
  448. y = pOffset->y;
  449. PATHOBJ_vOffset(ppo, x, y);
  450. CLIPOBJ_vOffset(pco, x, y);
  451. OFFSET_POINTL(pptlBrush, x, y);
  452. BOOL bRet = pfnStrokePath(pso, ppo, pco, pxo, pbo, pptlBrush, pla, mix);
  453. if ((bRet == FALSE) &&
  454. ((pla->fl & LA_GEOMETRIC) || (ppo->fl & PO_BEZIERS)))
  455. {
  456. // When given a wideline, or given a line composed of bezier curves,
  457. // the driver can return FALSE from DrvStrokePath to indicate that
  458. // it would like the drawing broken up into simpler Drv calls.
  459. // Unfortunately, this poses a problem for us because we might have
  460. // just drawn and succeeded an XOR DrvStrokePath to a different area.
  461. // If we returned FALSE, GDI would pop through the DrvStrokePath
  462. // path and touch all the areas again, thus erasing the DrvStrokePath
  463. // that is supposed to be drawn in the previous area!
  464. //
  465. // For this reason, we try not to return FALSE from optional calls.
  466. bRet = EngStrokePath(pso, ppo, pco, pxo, pbo, pptlBrush, pla, mix);
  467. }
  468. PATHOBJ_vOffset(ppo, -x, -y);
  469. CLIPOBJ_vOffset(pco, -x, -y);
  470. ASSERT_BRUSH_ORIGIN(pptlBrush, x, y);
  471. return(bRet);
  472. }
  473. /******************************Public*Routine******************************\
  474. * BOOL OffFillPath
  475. *
  476. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  477. * Wrote it.
  478. \**************************************************************************/
  479. BOOL OffFillPath(
  480. PFN_DrvFillPath pfnFillPath,
  481. POINTL* pOffset,
  482. SURFOBJ* pso,
  483. PATHOBJ* ppo,
  484. CLIPOBJ* pco,
  485. BRUSHOBJ* pbo,
  486. POINTL* pptlBrush,
  487. MIX mix,
  488. FLONG flOptions)
  489. {
  490. LONG x;
  491. LONG y;
  492. x = pOffset->x;
  493. y = pOffset->y;
  494. PATHOBJ_vOffset(ppo, x, y);
  495. CLIPOBJ_vOffset(pco, x, y);
  496. OFFSET_POINTL(pptlBrush, x, y);
  497. BOOL bRet = pfnFillPath(pso, ppo, pco, pbo, pptlBrush, mix, flOptions);
  498. if (bRet == FALSE)
  499. {
  500. // The driver can return FALSE from DrvFillPath to indicate that
  501. // it would like the drawing broken up into simpler Drv calls.
  502. // Unfortunately, this poses a problem for us because we might have
  503. // just drawn and succeeded an XOR DrvFillPath to a different area.
  504. // If we returned FALSE, GDI would pop through the DrvFillPath
  505. // path and touch all the areas again, thus erasing the DrvFillPath
  506. // that is supposed to be drawn in the previous area!
  507. //
  508. // For this reason, we try not to return FALSE from optional calls.
  509. bRet = EngFillPath(pso, ppo, pco, pbo, pptlBrush, mix, flOptions);
  510. }
  511. PATHOBJ_vOffset(ppo, -x, -y);
  512. CLIPOBJ_vOffset(pco, -x, -y);
  513. ASSERT_BRUSH_ORIGIN(pptlBrush, x, y);
  514. return(bRet);
  515. }
  516. /******************************Public*Routine******************************\
  517. * BOOL OffStrokeAndFillPath
  518. *
  519. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  520. * Wrote it.
  521. \**************************************************************************/
  522. BOOL OffStrokeAndFillPath(
  523. PFN_DrvStrokeAndFillPath pfnStrokeAndFillPath,
  524. POINTL* pOffset,
  525. SURFOBJ* pso,
  526. PATHOBJ* ppo,
  527. CLIPOBJ* pco,
  528. XFORMOBJ* pxo,
  529. BRUSHOBJ* pboStroke,
  530. LINEATTRS* pla,
  531. BRUSHOBJ* pboFill,
  532. POINTL* pptlBrush,
  533. MIX mixFill,
  534. FLONG flOptions)
  535. {
  536. LONG x;
  537. LONG y;
  538. x = pOffset->x;
  539. y = pOffset->y;
  540. PATHOBJ_vOffset(ppo, x, y);
  541. CLIPOBJ_vOffset(pco, x, y);
  542. OFFSET_POINTL(pptlBrush, x, y);
  543. BOOL bRet = pfnStrokeAndFillPath(pso, ppo, pco, pxo, pboStroke, pla,
  544. pboFill, pptlBrush, mixFill, flOptions);
  545. if (bRet == FALSE)
  546. {
  547. // The driver can return FALSE from DrvStrokeAndFillPath to indicate
  548. // that it would like the drawing broken up into simpler Drv calls.
  549. // Unfortunately, this poses a problem for us because we might have
  550. // just drawn and succeeded an XOR DrvStrokeAndFillPath to a different
  551. // area. If we returned FALSE, GDI would pop through the
  552. // DrvStrokeAndFillPath path and touch all the areas again, thus
  553. // erasing the DrvStrokeAndFillPath that is supposed to be drawn in
  554. // the previous area!
  555. //
  556. // For this reason, we try not to return FALSE from optional calls.
  557. bRet = EngStrokeAndFillPath(pso, ppo, pco, pxo, pboStroke, pla,
  558. pboFill, pptlBrush, mixFill, flOptions);
  559. }
  560. PATHOBJ_vOffset(ppo, -x, -y);
  561. CLIPOBJ_vOffset(pco, -x, -y);
  562. ASSERT_BRUSH_ORIGIN(pptlBrush, x, y);
  563. return(bRet);
  564. }
  565. /******************************Public*Routine******************************\
  566. * BOOL OffTextOut
  567. *
  568. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  569. * Wrote it.
  570. \**************************************************************************/
  571. BOOL OffTextOut(
  572. PFN_DrvTextOut pfnTextOut,
  573. POINTL* pOffset,
  574. SURFOBJ* pso,
  575. STROBJ* pstro,
  576. FONTOBJ* pfo,
  577. CLIPOBJ* pco,
  578. RECTL* prclExtra, // Not used by display drivers
  579. RECTL* prclOpaque,
  580. BRUSHOBJ* pboFore,
  581. BRUSHOBJ* pboOpaque,
  582. POINTL* pptlOrg, // Not used by display drivers
  583. MIX mix)
  584. {
  585. LONG x;
  586. LONG y;
  587. x = pOffset->x;
  588. y = pOffset->y;
  589. ASSERTGDI(prclExtra == NULL, "Unexpected non-NULL prclExtra");
  590. // Must offset a copy of 'prclOpaque' first because GDI sometimes
  591. // points 'prclOpaque' to '&pstro->rclBkGround', and so we would
  592. // do the offset twice.
  593. OFFSET_RECTL(prclOpaque, x, y);
  594. STROBJ_vOffset(pstro, x, y);
  595. CLIPOBJ_vOffset(pco, x, y);
  596. BOOL bRet = pfnTextOut(pso, pstro, pfo, pco, prclExtra, prclOpaque,
  597. pboFore, pboOpaque, pptlOrg, mix);
  598. STROBJ_vOffset(pstro, -x, -y);
  599. CLIPOBJ_vOffset(pco, -x, -y);
  600. return(bRet);
  601. }
  602. /******************************Public*Routine******************************\
  603. * BOOL OffLineTo
  604. *
  605. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  606. * Wrote it.
  607. \**************************************************************************/
  608. BOOL OffLineTo(
  609. PFN_DrvLineTo pfnLineTo,
  610. POINTL* pOffset,
  611. SURFOBJ* pso,
  612. CLIPOBJ* pco,
  613. BRUSHOBJ* pbo,
  614. LONG x1,
  615. LONG y1,
  616. LONG x2,
  617. LONG y2,
  618. RECTL* prclBounds,
  619. MIX mix)
  620. {
  621. LONG x;
  622. LONG y;
  623. x = pOffset->x;
  624. y = pOffset->y;
  625. CLIPOBJ_vOffset(pco, x, y);
  626. x1 += x;
  627. x2 += x;
  628. y1 += y;
  629. y2 += y;
  630. OFFSET_RECTL(prclBounds, x, y);
  631. BOOL bRet = pfnLineTo(pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix);
  632. if (!bRet)
  633. {
  634. // The driver can return FALSE from DrvLineTo to indicate that
  635. // it would like to instead by called via DrvStrokePath.
  636. // Unfortunately, this poses a problem for us because we might have
  637. // just drawn and succeeded an XOR DrvLineTo to a different area.
  638. // If we returned FALSE, GDI would pop through the DrvStrokePath
  639. // path and touch all the areas again, thus erasing the DrvLineTo
  640. // that is supposed to be drawn in the previous area!
  641. //
  642. // For this reason, we try not to return FALSE from optional calls.
  643. bRet = EngLineTo(pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix);
  644. }
  645. CLIPOBJ_vOffset(pco, -x, -y);
  646. return(bRet);
  647. }
  648. /******************************Public*Routine******************************\
  649. * BOOL OffGradientFill
  650. *
  651. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  652. * Wrote it.
  653. \**************************************************************************/
  654. BOOL OffGradientFill(
  655. PFN_DrvGradientFill pfnGradientFill,
  656. POINTL* pOffset,
  657. SURFOBJ* pso,
  658. CLIPOBJ* pco,
  659. XLATEOBJ* pxlo,
  660. TRIVERTEX* pVertex,
  661. ULONG nVertex,
  662. PVOID pMesh,
  663. ULONG nMesh,
  664. RECTL* prclExtents,
  665. POINTL* pptlDitherOrg,
  666. ULONG ulMode)
  667. {
  668. LONG x;
  669. LONG y;
  670. ULONG i;
  671. TRIVERTEX* pTmp;
  672. x = pOffset->x;
  673. y = pOffset->y;
  674. CLIPOBJ_vOffset(pco, x, y);
  675. OFFSET_RECTL(prclExtents, x, y);
  676. // The offseting of the dither origin is different than that of the other
  677. // data structures. The dither origin is defined to be the negative of
  678. // the offset of the window relative to the origin of the desktop surface.
  679. // The right value to pass to xxxGradientFill would be the negative of the
  680. // offset of the window relative to the origin of the sprite surface/
  681. // PDEV surface (for multimon). This is computed by subtracting the
  682. // pOffset from pptlDitherOrg.
  683. //
  684. // From definition of dither origin:
  685. // pptlDitherOrg = (-xWin_surf, -yWin_surf)
  686. //
  687. // From surface to desktop coordinate conversion:
  688. // (xWin_surf, yWin_surf) = (xWin_desk-xSurf_desk, yWin_desk-ySurf_desk)
  689. // where (xSurf_Desk, ySurf_desk) is the surface origin relative to the
  690. // desktop (corresponds to -pOffset in this function).
  691. //
  692. // Putting the two together, we get:
  693. // pptlDitherOrg = (-(xWin_desk-xSurf_desk), -(yWin_desk-ySurf_desk))=
  694. // = (-xWin_desk+xSurf_desk, -yWin_desk+ySurf_desk) =
  695. // = (-xWin_desk, -yWin_desk) + (xSurf_desk, ySurf_desk) =
  696. // = pptlDitherOrg_desk + (-pOffset)
  697. // = pptlDitherOrg_desk - pOffset
  698. //
  699. OFFSET_POINTL(pptlDitherOrg, (-x), (-y));
  700. for (pTmp = pVertex, i = 0; i < nVertex; i++, pTmp++)
  701. {
  702. pTmp->x += x;
  703. pTmp->y += y;
  704. }
  705. BOOL bRet = pfnGradientFill(pso, pco, pxlo, pVertex, nVertex, pMesh,
  706. nMesh, prclExtents, pptlDitherOrg, ulMode);
  707. CLIPOBJ_vOffset(pco, -x, -y);
  708. for (pTmp = pVertex, i = 0; i < nVertex; i++, pTmp++)
  709. {
  710. pTmp->x -= x;
  711. pTmp->y -= y;
  712. }
  713. return(bRet);
  714. }
  715. /******************************Public*Routine******************************\
  716. * BOOL OffBitBlt
  717. *
  718. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  719. * Wrote it.
  720. \**************************************************************************/
  721. BOOL OffBitBlt(
  722. PFN_DrvBitBlt pfnBitBlt,
  723. POINTL* pOffDst,
  724. SURFOBJ* psoDst,
  725. POINTL* pOffSrc,
  726. SURFOBJ* psoSrc,
  727. SURFOBJ* psoMsk,
  728. CLIPOBJ* pco,
  729. XLATEOBJ* pxlo,
  730. RECTL* prclDst,
  731. POINTL* pptlSrc,
  732. POINTL* pptlMsk,
  733. BRUSHOBJ* pbo,
  734. POINTL* pptlBrush,
  735. ROP4 rop4)
  736. {
  737. LONG xDst;
  738. LONG yDst;
  739. xDst = pOffDst->x;
  740. yDst = pOffDst->y;
  741. CLIPOBJ_vOffset(pco, xDst, yDst);
  742. OFFSET_RECTL_NOT_NULL(prclDst, xDst, yDst);
  743. OFFSET_POINTL(pptlSrc, pOffSrc->x, pOffSrc->y);
  744. OFFSET_POINTL(pptlBrush, xDst, yDst);
  745. ASSERTGDI((!psoSrc) ||
  746. (!(psoSrc->dhpdev) || !(psoDst->dhpdev)) ||
  747. (psoSrc->dhpdev == psoDst->dhpdev),
  748. "OffBitBlt: ERROR blitting across devices.");
  749. BOOL bRet = pfnBitBlt(psoDst, psoSrc, psoMsk, pco, pxlo, prclDst, pptlSrc,
  750. pptlMsk, pbo, pptlBrush, rop4);
  751. CLIPOBJ_vOffset(pco, -xDst, -yDst);
  752. ASSERT_BRUSH_ORIGIN(pptlBrush, xDst, yDst);
  753. return(bRet);
  754. }
  755. /******************************Public*Routine******************************\
  756. * BOOL OffCopyBits
  757. *
  758. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  759. * Wrote it.
  760. \**************************************************************************/
  761. BOOL OffCopyBits(
  762. PFN_DrvCopyBits pfnCopyBits,
  763. POINTL* pOffDst,
  764. SURFOBJ* psoDst,
  765. POINTL* pOffSrc,
  766. SURFOBJ* psoSrc,
  767. CLIPOBJ* pco,
  768. XLATEOBJ* pxlo,
  769. RECTL* prclDst,
  770. POINTL* pptlSrc)
  771. {
  772. LONG xDst;
  773. LONG yDst;
  774. LONG xSrc;
  775. LONG ySrc;
  776. xSrc = pOffSrc->x;
  777. ySrc = pOffSrc->y;
  778. xDst = pOffDst->x;
  779. yDst = pOffDst->y;
  780. if (pco != NULL)
  781. CLIPOBJ_vOffset(pco, xDst, yDst);
  782. OFFSET_RECTL_NOT_NULL(prclDst, xDst, yDst);
  783. OFFSET_POINTL_NOT_NULL(pptlSrc, xSrc, ySrc);
  784. ASSERTGDI((!psoSrc) ||
  785. (!(psoSrc->dhpdev) || !(psoDst->dhpdev)) ||
  786. (psoSrc->dhpdev == psoDst->dhpdev),
  787. "OffCopyBits: ERROR copying across devices.");
  788. // A defacto DDI rule is that on a CopyBits call, the bounds of a complex
  789. // clip object must intersect with the destination rectangle. This
  790. // is due to that fact that some drivers, such as the VGA driver, do not
  791. // bother checking for intersection with the destination rectangle when
  792. // enumerating a complex clip object. Thus, if this assert is hit, the
  793. // routine which constructed the clip object will have to be fixed. Note
  794. // that this is unrelated to sprites; I simply put this assert here because
  795. // it was a handy place for it, to check all CopyBits calls.
  796. ASSERTGDI((pco == NULL) ||
  797. (pco->iDComplexity == DC_TRIVIAL) ||
  798. bIntersect(&pco->rclBounds, prclDst),
  799. "Clip object bounds doesn't intersect destination rectangle");
  800. BOOL bRet = pfnCopyBits(psoDst, psoSrc, pco, pxlo, prclDst, pptlSrc);
  801. if (pco != NULL)
  802. CLIPOBJ_vOffset(pco, -xDst, -yDst);
  803. return(bRet);
  804. }
  805. /******************************Public*Routine******************************\
  806. * BOOL OffStretchBlt
  807. *
  808. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  809. * Wrote it.
  810. \**************************************************************************/
  811. BOOL OffStretchBlt(
  812. PFN_DrvStretchBlt pfnStretchBlt,
  813. POINTL* pOffDst,
  814. SURFOBJ* psoDst,
  815. POINTL* pOffSrc,
  816. SURFOBJ* psoSrc,
  817. SURFOBJ* psoMsk,
  818. CLIPOBJ* pco,
  819. XLATEOBJ* pxlo,
  820. COLORADJUSTMENT* pca,
  821. POINTL* pptlHTOrg,
  822. RECTL* prclDst,
  823. RECTL* prclSrc,
  824. POINTL* pptlMsk,
  825. ULONG iMode)
  826. {
  827. LONG xDst;
  828. LONG yDst;
  829. LONG xSrc;
  830. LONG ySrc;
  831. xSrc = pOffSrc->x;
  832. ySrc = pOffSrc->y;
  833. xDst = pOffDst->x;
  834. yDst = pOffDst->y;
  835. CLIPOBJ_vOffset(pco, xDst, yDst);
  836. OFFSET_RECTL_NOT_NULL(prclDst, xDst, yDst);
  837. OFFSET_RECTL_NOT_NULL(prclSrc, xSrc, ySrc);
  838. OFFSET_POINTL(pptlHTOrg, xDst, yDst);
  839. BOOL bRet = pfnStretchBlt(psoDst, psoSrc, psoMsk, pco, pxlo, pca,
  840. pptlHTOrg, prclDst, prclSrc, pptlMsk, iMode);
  841. CLIPOBJ_vOffset(pco, -xDst, -yDst);
  842. return(bRet);
  843. }
  844. /******************************Public*Routine******************************\
  845. * BOOL OffStretchBltROP
  846. *
  847. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  848. * Wrote it.
  849. \**************************************************************************/
  850. BOOL OffStretchBltROP(
  851. PFN_DrvStretchBltROP pfnStretchBltROP,
  852. POINTL* pOffDst,
  853. SURFOBJ* psoDst,
  854. POINTL* pOffSrc,
  855. SURFOBJ* psoSrc,
  856. SURFOBJ* psoMsk,
  857. CLIPOBJ* pco,
  858. XLATEOBJ* pxlo,
  859. COLORADJUSTMENT* pca,
  860. POINTL* pptlHTOrg,
  861. RECTL* prclDst,
  862. RECTL* prclSrc,
  863. POINTL* pptlMsk,
  864. ULONG iMode,
  865. BRUSHOBJ* pbo,
  866. DWORD rop4)
  867. {
  868. LONG xDst;
  869. LONG yDst;
  870. LONG xSrc;
  871. LONG ySrc;
  872. xSrc = pOffSrc->x;
  873. ySrc = pOffSrc->y;
  874. xDst = pOffDst->x;
  875. yDst = pOffDst->y;
  876. CLIPOBJ_vOffset(pco, xDst, yDst);
  877. OFFSET_RECTL(prclDst, xDst, yDst);
  878. OFFSET_RECTL(prclSrc, xSrc, ySrc);
  879. OFFSET_POINTL(pptlHTOrg, xDst, yDst);
  880. BOOL bRet = pfnStretchBltROP(psoDst, psoSrc, psoMsk, pco, pxlo, pca,
  881. pptlHTOrg, prclDst, prclSrc, pptlMsk, iMode,
  882. pbo, rop4);
  883. CLIPOBJ_vOffset(pco, -xDst, -yDst);
  884. return(bRet);
  885. }
  886. /******************************Public*Routine******************************\
  887. * BOOL OffTransparentBlt
  888. *
  889. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  890. * Wrote it.
  891. \**************************************************************************/
  892. BOOL OffTransparentBlt(
  893. PFN_DrvTransparentBlt pfnTransparentBlt,
  894. POINTL* pOffDst,
  895. SURFOBJ* psoDst,
  896. POINTL* pOffSrc,
  897. SURFOBJ* psoSrc,
  898. CLIPOBJ* pco,
  899. XLATEOBJ* pxlo,
  900. RECTL* prclDst,
  901. RECTL* prclSrc,
  902. ULONG iTransColor,
  903. ULONG ulReserved)
  904. {
  905. LONG xDst;
  906. LONG yDst;
  907. LONG xSrc;
  908. LONG ySrc;
  909. xSrc = pOffSrc->x;
  910. ySrc = pOffSrc->y;
  911. xDst = pOffDst->x;
  912. yDst = pOffDst->y;
  913. CLIPOBJ_vOffset(pco, xDst, yDst);
  914. OFFSET_RECTL(prclDst, xDst, yDst);
  915. OFFSET_RECTL(prclSrc, xSrc, ySrc);
  916. BOOL bRet = pfnTransparentBlt(psoDst, psoSrc, pco, pxlo, prclDst, prclSrc,
  917. iTransColor, ulReserved);
  918. CLIPOBJ_vOffset(pco, -xDst, -yDst);
  919. return(bRet);
  920. }
  921. /******************************Public*Routine******************************\
  922. * BOOL OffDrawStream
  923. *
  924. * 1-27-2001 bhouse
  925. * Wrote it.
  926. \**************************************************************************/
  927. BOOL OffDrawStream(
  928. PFN_DrvDrawStream pfnDrawStream,
  929. POINTL* pOffDst,
  930. SURFOBJ* psoDst,
  931. SURFOBJ* psoSrc,
  932. CLIPOBJ* pco,
  933. XLATEOBJ* pxlo,
  934. RECTL* prclDstBounds,
  935. POINTL* pptlDstOffset,
  936. ULONG ulIn,
  937. PVOID pvIn,
  938. DSSTATE* pdss
  939. )
  940. {
  941. LONG xDst;
  942. LONG yDst;
  943. LONG xSrc;
  944. LONG ySrc;
  945. xDst = pOffDst->x;
  946. yDst = pOffDst->y;
  947. CLIPOBJ_vOffset(pco, xDst, yDst);
  948. OFFSET_RECTL(prclDstBounds, xDst, yDst);
  949. OFFSET_POINTL(pptlDstOffset, xDst, yDst);
  950. BOOL bRet = pfnDrawStream(psoDst, psoSrc, pco, pxlo, prclDstBounds, pptlDstOffset, ulIn, pvIn, pdss);
  951. CLIPOBJ_vOffset(pco, -xDst, -yDst);
  952. return(bRet);
  953. }
  954. /******************************Public*Routine******************************\
  955. * BOOL OffAlphaBlend
  956. *
  957. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  958. * Wrote it.
  959. \**************************************************************************/
  960. BOOL OffAlphaBlend(
  961. PFN_DrvAlphaBlend pfnAlphaBlend,
  962. POINTL* pOffDst,
  963. SURFOBJ* psoDst,
  964. POINTL* pOffSrc,
  965. SURFOBJ* psoSrc,
  966. CLIPOBJ* pco,
  967. XLATEOBJ* pxlo,
  968. RECTL* prclDst,
  969. RECTL* prclSrc,
  970. BLENDOBJ* pBlendObj)
  971. {
  972. LONG xDst;
  973. LONG yDst;
  974. LONG xSrc;
  975. LONG ySrc;
  976. xSrc = pOffSrc->x;
  977. ySrc = pOffSrc->y;
  978. xDst = pOffDst->x;
  979. yDst = pOffDst->y;
  980. CLIPOBJ_vOffset(pco, xDst, yDst);
  981. OFFSET_RECTL(prclDst, xDst, yDst);
  982. OFFSET_RECTL(prclSrc, xSrc, ySrc);
  983. BOOL bRet = pfnAlphaBlend(psoDst, psoSrc, pco, pxlo, prclDst, prclSrc,
  984. pBlendObj);
  985. CLIPOBJ_vOffset(pco, -xDst, -yDst);
  986. return(bRet);
  987. }
  988. /******************************Public*Routine******************************\
  989. * BOOL OffPlgBlt
  990. *
  991. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  992. * Wrote it.
  993. \**************************************************************************/
  994. BOOL OffPlgBlt(
  995. PFN_DrvPlgBlt pfnPlgBlt,
  996. POINTL* pOffDst,
  997. SURFOBJ* psoDst,
  998. POINTL* pOffSrc,
  999. SURFOBJ* psoSrc,
  1000. SURFOBJ* psoMsk,
  1001. CLIPOBJ* pco,
  1002. XLATEOBJ* pxlo,
  1003. COLORADJUSTMENT* pca,
  1004. POINTL* pptlBrush,
  1005. POINTFIX* pptfx,
  1006. RECTL* prcl,
  1007. POINTL* pptlMsk,
  1008. ULONG iMode)
  1009. {
  1010. LONG xDst;
  1011. LONG yDst;
  1012. LONG xSrc;
  1013. LONG ySrc;
  1014. POINTFIX aptfx[3];
  1015. xSrc = pOffSrc->x;
  1016. ySrc = pOffSrc->y;
  1017. xDst = pOffDst->x;
  1018. yDst = pOffDst->y;
  1019. CLIPOBJ_vOffset(pco, xDst, yDst);
  1020. OFFSET_POINTL(pptlBrush, xDst, yDst);
  1021. OFFSET_RECTL(prcl, xSrc, ySrc);
  1022. aptfx[0].x = pptfx[0].x + (xDst << 4);
  1023. aptfx[1].x = pptfx[1].x + (xDst << 4);
  1024. aptfx[2].x = pptfx[2].x + (xDst << 4);
  1025. aptfx[0].y = pptfx[0].y + (yDst << 4);
  1026. aptfx[1].y = pptfx[1].y + (yDst << 4);
  1027. aptfx[2].y = pptfx[2].y + (yDst << 4);
  1028. BOOL bRet = pfnPlgBlt(psoDst, psoSrc, psoMsk, pco, pxlo, pca, pptlBrush,
  1029. aptfx, prcl, pptlMsk, iMode);
  1030. CLIPOBJ_vOffset(pco, -xDst, -yDst);
  1031. ASSERT_BRUSH_ORIGIN(pptlBrush, xDst, yDst);
  1032. return(bRet);
  1033. }
  1034. /******************************Public*Routine******************************\
  1035. * VOID vSpOrderInY
  1036. *
  1037. * Re-orders the sprite in the sorted-in-Y list.
  1038. *
  1039. * 'pSprite' must already be in the list, and all the other elements of the
  1040. * list must be properly sorted.
  1041. *
  1042. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1043. * Wrote it.
  1044. \**************************************************************************/
  1045. VOID vSpOrderInY(
  1046. SPRITE* pSprite)
  1047. {
  1048. LONG yThis;
  1049. SPRITE* pPrevious;
  1050. SPRITE* pNext;
  1051. ASSERTGDI(pSprite->pState->pListY != NULL,
  1052. "If there's a sprite, there should be a Y-list!");
  1053. yThis = pSprite->rclSprite.top;
  1054. if ((pSprite->pPreviousY != NULL) &&
  1055. (pSprite->pPreviousY->rclSprite.top > yThis))
  1056. {
  1057. // The sprite has to move up in the list. First, remove
  1058. // the sprite's node from its current position:
  1059. pPrevious = pSprite->pPreviousY;
  1060. pNext = pSprite->pNextY;
  1061. pPrevious->pNextY = pNext;
  1062. if (pNext)
  1063. pNext->pPreviousY = pPrevious;
  1064. // Find the sprite's proper position in the list:
  1065. pNext = pPrevious;
  1066. while (((pPrevious = pNext->pPreviousY) != NULL) &&
  1067. (pPrevious->rclSprite.top > yThis))
  1068. pNext = pPrevious;
  1069. // Insert the sprite in its new position:
  1070. pSprite->pPreviousY = pPrevious;
  1071. pSprite->pNextY = pNext;
  1072. pNext->pPreviousY = pSprite;
  1073. if (pPrevious)
  1074. pPrevious->pNextY = pSprite;
  1075. else
  1076. pSprite->pState->pListY = pSprite;
  1077. }
  1078. else if ((pSprite->pNextY != NULL) &&
  1079. (pSprite->pNextY->rclSprite.top < yThis))
  1080. {
  1081. // The sprite has to move down in the list. First, remove
  1082. // the sprite's node from its current position:
  1083. pNext = pSprite->pNextY;
  1084. pPrevious = pSprite->pPreviousY;
  1085. pNext->pPreviousY = pPrevious;
  1086. if (pPrevious)
  1087. pPrevious->pNextY = pNext;
  1088. else
  1089. pSprite->pState->pListY = pNext;
  1090. // Find the sprite's proper position in the list:
  1091. pPrevious = pNext;
  1092. while (((pNext = pPrevious->pNextY) != NULL) &&
  1093. (pNext->rclSprite.top < yThis))
  1094. pPrevious = pNext;
  1095. // Insert the sprite in its new position:
  1096. pSprite->pPreviousY = pPrevious;
  1097. pSprite->pNextY = pNext;
  1098. pPrevious->pNextY = pSprite;
  1099. if (pNext)
  1100. pNext->pPreviousY = pSprite;
  1101. }
  1102. }
  1103. /******************************Public*Routine******************************\
  1104. * VOID vSpComputeUncoveredRegion
  1105. *
  1106. * We construct the true RGNOBJ representing the uncovered portions of
  1107. * the screen directly from the sprite-range list.
  1108. *
  1109. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1110. * Wrote it.
  1111. \**************************************************************************/
  1112. VOID vSpComputeUncoveredRegion(
  1113. SPRITESTATE* pState)
  1114. {
  1115. REGION* prgnUncovered;
  1116. SIZE_T sizt;
  1117. // As a simple guess as to the size of the necessary region, we simply
  1118. // use the sprite-range size:
  1119. ASSERTGDI(sizeof(SPRITERANGE) + sizeof(SPRITESCAN) >= NULL_SCAN_SIZE,
  1120. "Our guess will be wrong!");
  1121. ASSERTGDI(pState->pRangeLimit > pState->pRange,
  1122. "pRange/pRangeLimit mismatch");
  1123. sizt = (BYTE*) pState->pRangeLimit - (BYTE*) pState->pRange;
  1124. // Add in the size of a header, which our sprite ranges don't have:
  1125. sizt += NULL_REGION_SIZE;
  1126. prgnUncovered = pState->prgnUncovered;
  1127. if (prgnUncovered->sizeObj < sizt)
  1128. {
  1129. // If the allocation fails, we'll simply stick with the old region
  1130. // and draw wrong (but we won't crash):
  1131. RGNMEMOBJ rmoNew((ULONGSIZE_T)sizt);
  1132. if (!rmoNew.bValid())
  1133. return;
  1134. RGNOBJ roOld(prgnUncovered);
  1135. roOld.vDeleteRGNOBJ();
  1136. prgnUncovered = rmoNew.prgnGet();
  1137. pState->prgnUncovered = prgnUncovered;
  1138. }
  1139. RGNOBJ roUncovered(pState->prgnUncovered);
  1140. PDEVOBJ po(pState->hdev);
  1141. roUncovered.vComputeUncoveredSpriteRegion(po);
  1142. roUncovered.vTighten();
  1143. ASSERTGDI(sizt >= roUncovered.sizeRgn(),
  1144. "Uh oh, we overwrote the end of the region!");
  1145. // Any DirectDraw locked areas have to be added back to the uncovered
  1146. // area:
  1147. if (pState->prgnUnlocked != NULL)
  1148. {
  1149. RGNOBJ roUnlocked(pState->prgnUnlocked);
  1150. RGNOBJ roTmp(pState->prgnTmp);
  1151. RGNMEMOBJTMP rmoLocked;
  1152. if (rmoLocked.bValid())
  1153. {
  1154. roTmp.vSet(&pState->rclScreen);
  1155. if (!rmoLocked.bMerge(roTmp, roUnlocked, gafjRgnOp[RGN_DIFF]))
  1156. {
  1157. rmoLocked.vSet();
  1158. }
  1159. if (!roTmp.bMerge(roUncovered, rmoLocked, gafjRgnOp[RGN_OR]))
  1160. {
  1161. roTmp.vSet();
  1162. }
  1163. pState->prgnUncovered = roTmp.prgnGet();
  1164. pState->prgnTmp = roUncovered.prgnGet();
  1165. }
  1166. }
  1167. pState->prgnUncovered->vStamp();
  1168. }
  1169. /******************************Public*Routine******************************\
  1170. * VOID vSpSetNullRange
  1171. *
  1172. * Resets the sprite range to a null area.
  1173. *
  1174. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1175. * Wrote it.
  1176. \**************************************************************************/
  1177. VOID vSpSetNullRange(
  1178. SPRITESTATE* pState,
  1179. SPRITESCAN* pScan) // Must be pool allocated (it will be freed later)
  1180. // and at least sizeof(SPRITESCAN)
  1181. {
  1182. pScan->yTop = pState->rclScreen.top;
  1183. pScan->yBottom = pState->rclScreen.bottom;
  1184. pScan->siztScan = sizeof(SPRITESCAN);
  1185. pScan->siztPrevious = 0;
  1186. pScan->aRange[0].xLeft = pState->rclScreen.left;
  1187. pScan->aRange[0].xRight = pState->rclScreen.right;
  1188. pScan->aRange[0].pSprite = NULL;
  1189. pState->pRange = pScan;
  1190. pState->pRangeLimit = pScan + 1;
  1191. }
  1192. #define BATCH_ALLOC_COUNT 20
  1193. inline SPRITERANGE* pSpRangeLimit(
  1194. SPRITESTATE* pState)
  1195. {
  1196. // We adjust the range limit to leave room for that extra SPRITESCAN
  1197. // structure we allocated. It's also VERY important that we remove a
  1198. // SPRITERANGE structure to account for sizeof(SPRITERANGE) not
  1199. // dividing evenly into sizeof(SPRITESCAN):
  1200. return((SPRITERANGE*) ((BYTE*) pState->pRangeLimit
  1201. - sizeof(SPRITESCAN) - sizeof(SPRITERANGE)));
  1202. }
  1203. /******************************Public*Routine******************************\
  1204. * SPRITERANGE* pSpGrowRanges
  1205. *
  1206. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1207. * Wrote it.
  1208. \**************************************************************************/
  1209. SPRITERANGE* pSpGrowRanges(
  1210. SPRITESTATE* pState,
  1211. SPRITERANGE* pCurrentRange,
  1212. SPRITESCAN** ppCurrentScan,
  1213. SPRITERANGE** ppRangeLimit)
  1214. {
  1215. SPRITESCAN* pNewRegion;
  1216. SIZE_T siztOldAlloc;
  1217. SIZE_T siztNewAlloc;
  1218. SIZE_T siztCurrentRange;
  1219. SIZE_T siztCurrentScan;
  1220. #if DEBUG_SPRITES
  1221. KdPrint(("GDI: Growing sprite ranges\n"));
  1222. #endif
  1223. // We always add in the size of a SPRITESCAN structure to allow
  1224. // 'bSpComputeScan' to initialize it without checking:
  1225. siztCurrentRange = (BYTE*) pCurrentRange - (BYTE*) pState->pRange;
  1226. siztCurrentScan = (BYTE*) *ppCurrentScan - (BYTE*) pState->pRange;
  1227. siztOldAlloc = (BYTE*) pState->pRangeLimit - (BYTE*) pState->pRange;
  1228. siztNewAlloc = siztOldAlloc + sizeof(SPRITESCAN)
  1229. + sizeof(SPRITERANGE) * BATCH_ALLOC_COUNT;
  1230. pNewRegion = (SPRITESCAN*) PALLOCNOZ((ULONGSIZE_T)siztNewAlloc, 'rpsG');
  1231. if (pNewRegion == NULL)
  1232. {
  1233. vSpSetNullRange(pState, pState->pRange);
  1234. // Should we mark every sprite as invisible?
  1235. return(NULL);
  1236. }
  1237. RtlCopyMemory(pNewRegion, pState->pRange, siztCurrentRange);
  1238. VFREEMEM(pState->pRange);
  1239. pState->pRange = pNewRegion;
  1240. pState->pRangeLimit = (BYTE*) pNewRegion + siztNewAlloc;
  1241. *ppCurrentScan = (SPRITESCAN*) ((BYTE*) pNewRegion + siztCurrentScan);
  1242. *ppRangeLimit = pSpRangeLimit(pState);
  1243. return((SPRITERANGE*) ((BYTE*) pNewRegion + siztCurrentRange));
  1244. }
  1245. /******************************Public*Routine******************************\
  1246. * BOOL bSpComputeScan
  1247. *
  1248. * 12-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1249. * Wrote it.
  1250. \**************************************************************************/
  1251. BOOL bSpComputeScan(
  1252. SPRITESTATE* pState,
  1253. SPRITE* pActiveList,
  1254. LONG yTop,
  1255. LONG yBottom,
  1256. SPRITESCAN** ppScan,
  1257. SIZE_T* psiztPrevious)
  1258. {
  1259. SPRITESCAN* pScan;
  1260. SPRITERANGE* pRange;
  1261. SPRITERANGE* pRangeLimit;
  1262. SPRITERANGE* pTmp;
  1263. SPRITE* pSprite;
  1264. LONG xLeft;
  1265. LONG xRight;
  1266. LONG xFinalRight;
  1267. LONG cSprites;
  1268. ASSERTGDI(yTop < yBottom, "Invalid empty row");
  1269. xLeft = pState->rclScreen.left;
  1270. xRight = pState->rclScreen.right;
  1271. xFinalRight = pState->rclScreen.right;
  1272. pScan = *ppScan;
  1273. pScan->yTop = yTop;
  1274. pScan->yBottom = yBottom;
  1275. pScan->siztPrevious = *psiztPrevious;
  1276. pRangeLimit = pSpRangeLimit(pState);
  1277. pRange = &pScan->aRange[0];
  1278. // Note that we always adjust 'pRangeLimit' to leave room for a
  1279. // SPRITESCAN structure:
  1280. ASSERTGDI((pScan >= (SPRITESCAN*) pState->pRange) &&
  1281. (pScan + 1 <= (SPRITESCAN*) pState->pRangeLimit),
  1282. "pScan will overwrite buffer end!");
  1283. ASSERTGDI(pState->pRange < pState->pRangeLimit,
  1284. "pRange/pRangeLimit mismatch");
  1285. do {
  1286. cSprites = 0;
  1287. for (pSprite = pActiveList;
  1288. pSprite != NULL;
  1289. pSprite = pSprite->pNextActive)
  1290. {
  1291. ASSERTGDI((pSprite != NULL) &&
  1292. (pSprite->rclSprite.top <= yTop) &&
  1293. (pSprite->rclSprite.bottom >= yBottom) &&
  1294. (pSprite->rclSprite.left < pSprite->rclSprite.right) &&
  1295. (pSprite->rclSprite.top < pSprite->rclSprite.bottom),
  1296. "Invalid active list");
  1297. if (pSprite->rclSprite.left <= xLeft)
  1298. {
  1299. if (pSprite->rclSprite.right > xLeft)
  1300. {
  1301. cSprites++;
  1302. // Add this sprite:
  1303. if (pRange >= pRangeLimit)
  1304. {
  1305. pRange = pSpGrowRanges(pState,
  1306. pRange,
  1307. &pScan,
  1308. &pRangeLimit);
  1309. if (!pRange)
  1310. return(FALSE);
  1311. }
  1312. pRange->pSprite = pSprite;
  1313. pRange++;
  1314. if (pSprite->rclSprite.right <= xRight)
  1315. xRight = pSprite->rclSprite.right;
  1316. }
  1317. }
  1318. else if (pSprite->rclSprite.left <= xRight)
  1319. {
  1320. xRight = pSprite->rclSprite.left;
  1321. }
  1322. }
  1323. if (cSprites == 0)
  1324. {
  1325. if (pRange >= pRangeLimit)
  1326. {
  1327. pRange = pSpGrowRanges(pState, pRange, &pScan, &pRangeLimit);
  1328. if (!pRange)
  1329. return(FALSE);
  1330. }
  1331. pRange->pSprite = NULL;
  1332. pRange->xLeft = xLeft;
  1333. pRange->xRight = xRight;
  1334. pRange++;
  1335. }
  1336. else
  1337. {
  1338. // Now, fill in the wall values for every range we just
  1339. // put down:
  1340. pTmp = pRange;
  1341. do {
  1342. pTmp--;
  1343. pTmp->xLeft = xLeft;
  1344. pTmp->xRight = xRight;
  1345. } while (--cSprites != 0);
  1346. }
  1347. // Advance to the next rectangle in this scan:
  1348. xLeft = xRight;
  1349. xRight = xFinalRight;
  1350. } while (xLeft < xRight);
  1351. pScan->siztScan = (BYTE*) pRange - (BYTE*) pScan;
  1352. *psiztPrevious = pScan->siztScan;
  1353. *ppScan = (SPRITESCAN*) pRange;
  1354. return(TRUE);
  1355. }
  1356. /******************************Public*Routine******************************\
  1357. * BOOL vSpComputeSpriteRanges
  1358. *
  1359. * Recalculates the 'range' list that describes how the overlays overlap
  1360. * the screen.
  1361. *
  1362. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1363. * Wrote it.
  1364. \**************************************************************************/
  1365. VOID vSpComputeSpriteRanges(
  1366. SPRITESTATE* pState)
  1367. {
  1368. SPRITE* pPrevious;
  1369. SPRITE* pNext;
  1370. SPRITE* pThis;
  1371. SPRITE* pSpriteY;
  1372. BOOL bSprite;
  1373. SPRITE ActiveHead;
  1374. LONG yTop;
  1375. LONG yBottom;
  1376. LONG yFinalBottom;
  1377. SPRITESCAN* pCurrentScan;
  1378. SIZE_T siztPrevious;
  1379. ASSERTGDI(!(pState->bValidRange),
  1380. "Should be called only when dirty.");
  1381. pCurrentScan = pState->pRange;
  1382. siztPrevious = 0;
  1383. ActiveHead.pNextActive = NULL;
  1384. yTop = pState->rclScreen.top;
  1385. yBottom = pState->rclScreen.bottom;
  1386. yFinalBottom = pState->rclScreen.bottom;
  1387. // First, skip over any invisible sprites:
  1388. pSpriteY = pState->pListY;
  1389. while ((pSpriteY != NULL) && (pSpriteY->rclSprite.bottom <= yTop))
  1390. pSpriteY = pSpriteY->pNextY;
  1391. do {
  1392. // Prune the active list, throwing out anyone whose bottom
  1393. // matches the previous row's bottom, and at the same time
  1394. // compute the new bottom:
  1395. pPrevious = &ActiveHead;
  1396. while ((pThis = pPrevious->pNextActive) != NULL)
  1397. {
  1398. if (pThis->rclSprite.bottom == yTop)
  1399. {
  1400. pPrevious->pNextActive = pThis->pNextActive;
  1401. }
  1402. else
  1403. {
  1404. if (pThis->rclSprite.bottom <= yBottom)
  1405. yBottom = pThis->rclSprite.bottom;
  1406. // Advance to next node:
  1407. pPrevious = pThis;
  1408. }
  1409. }
  1410. // Add to the active list any sprites that have a 'top'
  1411. // value equal to the new top, watching out for a new
  1412. // 'bottom' value:
  1413. while (pSpriteY != NULL)
  1414. {
  1415. if (pSpriteY->rclSprite.top != yTop)
  1416. {
  1417. // Any not-yet-used sprites may affect the height of
  1418. // this row:
  1419. if (pSpriteY->rclSprite.top <= yBottom)
  1420. yBottom = pSpriteY->rclSprite.top;
  1421. break; // =======>
  1422. }
  1423. // The active list is kept in back-to-front z-order:
  1424. pNext = &ActiveHead;
  1425. do {
  1426. pPrevious = pNext;
  1427. pNext = pPrevious->pNextActive;
  1428. } while ((pNext != NULL) && (pNext->z < pSpriteY->z));
  1429. pPrevious->pNextActive = pSpriteY;
  1430. pSpriteY->pNextActive = pNext;
  1431. if (pSpriteY->rclSprite.bottom <= yBottom)
  1432. yBottom = pSpriteY->rclSprite.bottom;
  1433. pSpriteY = pSpriteY->pNextY;
  1434. }
  1435. // Now, use the active-list to compute the new row:
  1436. if (!bSpComputeScan(pState,
  1437. ActiveHead.pNextActive,
  1438. yTop,
  1439. yBottom,
  1440. &pCurrentScan,
  1441. &siztPrevious))
  1442. {
  1443. // In case of failure, 'bSpComputeScan' leaves the structure
  1444. // empty but consistent, so we can safely just leave:
  1445. return;
  1446. }
  1447. // Advance to the next row:
  1448. yTop = yBottom;
  1449. yBottom = yFinalBottom;
  1450. } while (yTop < yBottom);
  1451. // The range cache is now valid:
  1452. pState->bValidRange = TRUE;
  1453. // Finally, use the sprite range to compute a true region representing
  1454. // the uncovered parts:
  1455. vSpComputeUncoveredRegion(pState);
  1456. }
  1457. /******************************Public*Routine******************************\
  1458. * ENUMAREAS::ENUMAREAS
  1459. *
  1460. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1461. * Wrote it.
  1462. \**************************************************************************/
  1463. ENUMAREAS::ENUMAREAS(
  1464. SPRITESTATE* pState,
  1465. RECTL* prclBounds, // Must be pre-clipped to screen
  1466. ULONG iDirection) // CD_RIGHTDOWN is the default
  1467. {
  1468. LONG yStart;
  1469. SPRITESCAN* pTmpScan;
  1470. SPRITERANGE* pTmpRange;
  1471. if (!pState->bValidRange)
  1472. {
  1473. vSpComputeSpriteRanges(pState);
  1474. }
  1475. bValidRange = pState->bValidRange; // valid only if the sprite range
  1476. // computation succeeded
  1477. // BUGFIX #22140 2-18-2000 bhouse
  1478. // We will just leave this assertion code commented out for now. If we
  1479. // ever have a bug causing us to fix the how we calculate the bounds
  1480. // in BLTRECORD__bRotate then perhaps we can un-comment out these
  1481. // lines.
  1482. // ASSERTGDI((prclBounds->left >= pState->rclScreen.left) &&
  1483. // (prclBounds->top >= pState->rclScreen.top)),
  1484. // "invalid rectangle");
  1485. ASSERTGDI((prclBounds->right <= pState->rclScreen.right) &&
  1486. (prclBounds->bottom <= pState->rclScreen.bottom) &&
  1487. (prclBounds->left < prclBounds->right) &&
  1488. (prclBounds->top < prclBounds->bottom),
  1489. "Invalid rectangle specified");
  1490. iDir = iDirection;
  1491. xBoundsLeft = prclBounds->left;
  1492. xBoundsRight = prclBounds->right;
  1493. yBoundsTop = prclBounds->top;
  1494. yBoundsBottom = prclBounds->bottom;
  1495. // Find the first scan that contains the start 'y' value:
  1496. yStart = (iDirection & 2) ? (yBoundsBottom - 1) : (yBoundsTop);
  1497. pTmpScan = pState->pRange;
  1498. while (pTmpScan->yBottom <= yStart)
  1499. pTmpScan = pSpNextScan(pTmpScan);
  1500. // If more than one sprite overlaps a region, there will be
  1501. // multiple sprite-range records for the same area. When
  1502. // going left-to-right, we should leave 'pTmpRange' pointing to
  1503. // the start of this sequence; when going right-to-left, we
  1504. // should leave 'pTmpRange' pointing to the end of this sequence.
  1505. if ((iDirection & 1) == 0) // Left-to-right
  1506. {
  1507. pTmpRange = &pTmpScan->aRange[0];
  1508. while (pTmpRange->xRight <= xBoundsLeft)
  1509. pTmpRange++;
  1510. }
  1511. else // Right-to-left
  1512. {
  1513. pTmpRange = pSpLastRange(pTmpScan);
  1514. while (pTmpRange->xLeft >= xBoundsRight)
  1515. pTmpRange--;
  1516. }
  1517. yTop = max(pTmpScan->yTop, yBoundsTop);
  1518. yBottom = min(pTmpScan->yBottom, yBoundsBottom);
  1519. // We used temporary variables as opposed to the structure members
  1520. // directly so that the compiler would be more efficient:
  1521. pScan = pTmpScan;
  1522. pRange = pTmpRange;
  1523. }
  1524. /******************************Public*Routine******************************\
  1525. * BOOL ENUMAREAS::bEnum
  1526. *
  1527. * This routine enumerates the list of sprite and non-sprite ranges
  1528. * comprising a rectangular area on the screen. If two sprites overlap,
  1529. * for the overlapping rectangle this routine will always return the
  1530. * bottom-most sprite.
  1531. *
  1532. * Returns TRUE if more ranges after this remain to be enumerated.
  1533. *
  1534. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1535. * Wrote it.
  1536. \**************************************************************************/
  1537. BOOL ENUMAREAS::bEnum(
  1538. SPRITE** ppSprite, // Returns touched sprite. This will be NULL
  1539. // if the enumerated area is touched by
  1540. // no sprite
  1541. RECTL* prclSprite) // Returns area of sprite touched
  1542. {
  1543. SPRITESCAN* pTmpScan;
  1544. SPRITERANGE* pTmpRange;
  1545. // Use local variables where possible to be more efficient in our
  1546. // inner loops:
  1547. pTmpRange = pRange;
  1548. // Remember some state for enumerating the layers:
  1549. pRangeLayer = pTmpRange;
  1550. pScanLayer = pScan;
  1551. // Fill in details about the current range:
  1552. *ppSprite = pTmpRange->pSprite;
  1553. prclSprite->left = max(pTmpRange->xLeft, xBoundsLeft);
  1554. prclSprite->right = min(pTmpRange->xRight, xBoundsRight);
  1555. prclSprite->top = yTop;
  1556. prclSprite->bottom = yBottom;
  1557. ASSERTGDI((prclSprite->left < prclSprite->right) &&
  1558. (prclSprite->top < prclSprite->bottom),
  1559. "Invalid return rectangle");
  1560. ASSERTGDI((*ppSprite == NULL) ||
  1561. (((*ppSprite)->rclSprite.left <= prclSprite->left) &&
  1562. ((*ppSprite)->rclSprite.top <= prclSprite->top) &&
  1563. ((*ppSprite)->rclSprite.right >= prclSprite->right) &&
  1564. ((*ppSprite)->rclSprite.bottom >= prclSprite->bottom)),
  1565. "Invalid return sprite");
  1566. if ((iDir & 1) == 0) // Left-to-right
  1567. {
  1568. if (pTmpRange->xRight < xBoundsRight)
  1569. {
  1570. do {
  1571. pTmpRange++;
  1572. } while ((pTmpRange - 1)->xLeft == pTmpRange->xLeft);
  1573. }
  1574. else
  1575. {
  1576. pTmpScan = pScan;
  1577. if (iDir == CD_RIGHTDOWN)
  1578. {
  1579. if (pTmpScan->yBottom >= yBoundsBottom)
  1580. return(FALSE);
  1581. pTmpScan = pSpNextScan(pTmpScan);
  1582. }
  1583. else
  1584. {
  1585. ASSERTGDI(iDir == CD_RIGHTUP, "Unexpected iDir");
  1586. if (pTmpScan->yTop <= yBoundsTop)
  1587. return(FALSE);
  1588. pTmpScan = pSpPreviousScan(pTmpScan);
  1589. }
  1590. pScan = pTmpScan;
  1591. yTop = max(pTmpScan->yTop, yBoundsTop);
  1592. yBottom = min(pTmpScan->yBottom, yBoundsBottom);
  1593. pTmpRange = &pTmpScan->aRange[0];
  1594. while (pTmpRange->xRight <= xBoundsLeft)
  1595. pTmpRange++;
  1596. }
  1597. }
  1598. else // Right-to-left
  1599. {
  1600. if (pTmpRange->xLeft > xBoundsLeft)
  1601. {
  1602. do {
  1603. pTmpRange--;
  1604. } while ((pTmpRange + 1)->xLeft == pTmpRange->xLeft);
  1605. }
  1606. else
  1607. {
  1608. pTmpScan = pScan;
  1609. if (iDir == CD_LEFTDOWN)
  1610. {
  1611. if (pTmpScan->yBottom >= yBoundsBottom)
  1612. return(FALSE);
  1613. pTmpScan = pSpNextScan(pTmpScan);
  1614. }
  1615. else
  1616. {
  1617. ASSERTGDI(iDir == CD_LEFTUP, "Unexpected iDir");
  1618. if (pTmpScan->yTop <= yBoundsTop)
  1619. return(FALSE);
  1620. pTmpScan = pSpPreviousScan(pTmpScan);
  1621. }
  1622. pScan = pTmpScan;
  1623. yTop = max(pTmpScan->yTop, yBoundsTop);
  1624. yBottom = min(pTmpScan->yBottom, yBoundsBottom);
  1625. pTmpRange = pSpLastRange(pTmpScan);
  1626. while (pTmpRange->xLeft >= xBoundsRight)
  1627. pTmpRange--;
  1628. }
  1629. }
  1630. pRange = pTmpRange;
  1631. return(TRUE);
  1632. }
  1633. /******************************Public*Routine******************************\
  1634. * ENUMUNCOVERED::ENUMUNCOVERED
  1635. *
  1636. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1637. * Wrote it.
  1638. \**************************************************************************/
  1639. ENUMUNCOVERED::ENUMUNCOVERED(
  1640. SPRITESTATE* pState)
  1641. {
  1642. if (!pState->bValidRange)
  1643. {
  1644. vSpComputeSpriteRanges(pState);
  1645. }
  1646. yBoundsBottom = pState->rclScreen.bottom;
  1647. pScan = pState->pRange;
  1648. pRange = &pScan->aRange[0] - 1;
  1649. pNextScan = pSpNextScan(pScan);
  1650. }
  1651. /******************************Public*Routine******************************\
  1652. * BOOL ENUMUNCOVERED::bEnum
  1653. *
  1654. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1655. * Wrote it.
  1656. \**************************************************************************/
  1657. BOOL ENUMUNCOVERED::bEnum(
  1658. RECTL* prclUncovered)
  1659. {
  1660. SPRITESCAN* pTmpScan = pScan;
  1661. SPRITERANGE* pTmpRange = pRange;
  1662. do {
  1663. pTmpRange++;
  1664. if (pTmpRange >= (SPRITERANGE*) pNextScan)
  1665. {
  1666. if (pTmpScan->yBottom >= yBoundsBottom)
  1667. return(FALSE);
  1668. pTmpScan = pNextScan;
  1669. pNextScan = pSpNextScan(pNextScan);
  1670. pTmpRange = &pTmpScan->aRange[0];
  1671. }
  1672. } while (pTmpRange->pSprite != NULL);
  1673. prclUncovered->top = pTmpScan->yTop;
  1674. prclUncovered->bottom = pTmpScan->yBottom;
  1675. prclUncovered->left = pTmpRange->xLeft;
  1676. prclUncovered->right = pTmpRange->xRight;
  1677. pScan = pTmpScan;
  1678. pRange = pTmpRange;
  1679. return(TRUE);
  1680. }
  1681. /******************************Public*Routine******************************\
  1682. * BOOL ENUMAREAS::bEnumLayers
  1683. *
  1684. * This routine may be called only after 'bEnum' is called, and lists
  1685. * the sprites that overlay the 'bEnum' rectangle, bottom-most to top-most.
  1686. *
  1687. * Returns TRUE if the returned 'ppSprite' is a valid layer.
  1688. *
  1689. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1690. * Wrote it.
  1691. \**************************************************************************/
  1692. BOOL ENUMAREAS::bEnumLayers(
  1693. SPRITE** ppSprite)
  1694. {
  1695. BOOL bRet = FALSE;
  1696. if ((iDir & 1) == 0) // Left-to-right
  1697. {
  1698. if ((pRangeLayer < pSpLastRange(pScanLayer)) &&
  1699. ((pRangeLayer + 1)->xLeft == pRangeLayer->xLeft))
  1700. {
  1701. pRangeLayer++;
  1702. bRet = TRUE;
  1703. }
  1704. }
  1705. else // Right-to-left
  1706. {
  1707. if ((pRangeLayer > &pScanLayer->aRange[0]) &&
  1708. ((pRangeLayer - 1)->xLeft == pRangeLayer->xLeft))
  1709. {
  1710. pRangeLayer--;
  1711. bRet = TRUE;
  1712. }
  1713. }
  1714. *ppSprite = pRangeLayer->pSprite;
  1715. return(bRet);
  1716. }
  1717. /******************************Public*Routine******************************\
  1718. * BOOL ENUMAREAS::bAdvanceToTopMostOpaqueLayer
  1719. *
  1720. * This routine may be called only after 'bEnum' is called, and advances
  1721. * to the top-most, unclipped opaque layer for this range.
  1722. *
  1723. * Returns TRUE if there was an opaque layer; FALSE if not.
  1724. *
  1725. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1726. * Wrote it.
  1727. \**************************************************************************/
  1728. BOOL ENUMAREAS::bAdvanceToTopMostOpaqueLayer(
  1729. SPRITE** ppSprite)
  1730. {
  1731. SPRITERANGE* pThis;
  1732. SPRITERANGE* pLast;
  1733. SPRITERANGE* pOpaque;
  1734. SPRITE* pSprite;
  1735. REGION* prgnClip;
  1736. BOOL bRet;
  1737. ASSERTGDI((iDir & 1) == 0, "Can use only when enumerating left-to-right");
  1738. pLast = pSpLastRange(pScanLayer);
  1739. pThis = pRangeLayer;
  1740. pOpaque = NULL;
  1741. // We can't do the opaque trick if any WNDOBJs are present on the screen,
  1742. // because we rely on the background repainting to refresh any sprites
  1743. // unveiled when a WNDOBJ moves.
  1744. if (gpto != NULL)
  1745. {
  1746. while (TRUE)
  1747. {
  1748. pSprite = pThis->pSprite;
  1749. if (pSprite->fl & SPRITE_FLAG_EFFECTIVELY_OPAQUE)
  1750. {
  1751. // Do a quick check to make sure this opaque sprite isn't
  1752. // clipped for this range.
  1753. prgnClip = pSprite->prgnClip;
  1754. if ((prgnClip == NULL) ||
  1755. ((prgnClip->sizeRgn <= SINGLE_REGION_SIZE) &&
  1756. (prgnClip->rcl.left <= pThis->xLeft) &&
  1757. (prgnClip->rcl.right >= pThis->xRight) &&
  1758. (prgnClip->rcl.top <= yTop) &&
  1759. (prgnClip->rcl.bottom >= yBottom)))
  1760. {
  1761. pOpaque = pThis;
  1762. }
  1763. }
  1764. if ((pThis >= pLast) || ((pThis + 1)->xLeft != pThis->xLeft))
  1765. break;
  1766. pThis++;
  1767. }
  1768. }
  1769. bRet = FALSE;
  1770. if (pOpaque)
  1771. {
  1772. pRangeLayer = pOpaque;
  1773. bRet = TRUE;
  1774. }
  1775. *ppSprite = pRangeLayer->pSprite;
  1776. return(bRet);
  1777. }
  1778. /******************************Public*Routine******************************\
  1779. * VOID vSpReadFromScreen
  1780. *
  1781. * All reads from the screen should be routed through this call so that
  1782. * we can:
  1783. *
  1784. * 1. Exclude any DirectDraw locked regions;
  1785. * 2. Respect any WNDOBJ boundaries.
  1786. *
  1787. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1788. * Wrote it.
  1789. \**************************************************************************/
  1790. VOID vSpReadFromScreen(
  1791. SPRITESTATE* pState,
  1792. POINTL* pOffDst,
  1793. SURFOBJ* psoDst,
  1794. RECTL* prclDst)
  1795. {
  1796. ECLIPOBJ ecoUnlocked;
  1797. ECLIPOBJ* pcoUnlocked;
  1798. pcoUnlocked = NULL;
  1799. if (pState->prgnUnlocked != NULL)
  1800. {
  1801. ecoUnlocked.vSetup(pState->prgnUnlocked, *(ERECTL*)prclDst);
  1802. if (ecoUnlocked.erclExclude().bEmpty())
  1803. return; // ======>
  1804. pcoUnlocked = &ecoUnlocked;
  1805. }
  1806. XLATEOBJ* pxlo = NULL;
  1807. SURFOBJ* psoSrc = pState->psoScreen;
  1808. PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
  1809. EXLATEOBJ xloParent;
  1810. POINTL* pOffSrc = &gptlZero;
  1811. PFN_DrvCopyBits pfnCopyBits;
  1812. PDEVOBJ pdoSrc(pSurfSrc->hdev());
  1813. // If source is mirror driver, redirect the call to DDML.
  1814. if (pSurfSrc->bMirrorSurface() &&
  1815. (pdoSrc.hdev() != pdoSrc.hdevParent()))
  1816. {
  1817. pOffSrc = pdoSrc.pptlOrigin();
  1818. PDEVOBJ pdoParent(pdoSrc.hdevParent());
  1819. SURFREF srParent((HSURF)pSurfSrc->hMirrorParent);
  1820. if (!srParent.bValid()) return;
  1821. if (xloParent.bInitXlateObj(
  1822. NULL,DC_ICM_OFF,
  1823. pdoParent.ppalSurf(), pdoSrc.ppalSurf(),
  1824. ppalDefault, ppalDefault,
  1825. 0L,0L,0L, XLATE_USE_SURFACE_PAL))
  1826. pxlo = xloParent.pxlo();
  1827. else
  1828. return;
  1829. psoSrc = srParent.ps->pSurfobj();
  1830. pfnCopyBits = PPFNDRV(pdoParent, CopyBits);
  1831. }
  1832. else if (!(SURFOBJ_TO_SURFACE_NOT_NULL(psoDst)->flags() & HOOK_CopyBits) &&
  1833. (psoSrc->hdev))
  1834. {
  1835. pfnCopyBits = PPFNDIRECT(psoSrc, CopyBits);
  1836. }
  1837. else
  1838. {
  1839. pfnCopyBits = PPFNDIRECT(psoDst, CopyBits);
  1840. }
  1841. // WINBUG #440135 10-02-2001 kchiu
  1842. // Instead of always passing &gptlZero for pOffSrc. We now pass in pdoSrc->pptlOrigin() whenever
  1843. // the source is mirror driver. We do this for mirror driver only and not for secondary drivers
  1844. // with non-zero origin because the coords are already offset correctly in the case of a secondary
  1845. // driver, but not in the case of the mirror driver.
  1846. OffCopyBits(pfnCopyBits,
  1847. pOffDst,
  1848. psoDst,
  1849. pOffSrc,
  1850. psoSrc,
  1851. pcoUnlocked,
  1852. pxlo,
  1853. prclDst,
  1854. (POINTL*) prclDst);
  1855. }
  1856. /******************************Public*Routine******************************\
  1857. * VOID vSpWriteToScreen
  1858. *
  1859. * All writes to the screen should be routed through this call so that
  1860. * we can:
  1861. *
  1862. * 1. Exclude any DirectDraw locked regions;
  1863. * 2. Respect any WNDOBJ boundaries.
  1864. *
  1865. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1866. * Wrote it.
  1867. \**************************************************************************/
  1868. VOID vSpWriteToScreen(
  1869. SPRITESTATE* pState,
  1870. POINTL* pOffSrc,
  1871. SURFOBJ* psoSrc,
  1872. RECTL* prclSrc)
  1873. {
  1874. GDIFunctionID(vSpWriteToScreen);
  1875. ECLIPOBJ ecoUnlocked;
  1876. ECLIPOBJ* pcoUnlocked;
  1877. pcoUnlocked = NULL;
  1878. if (pState->prgnUnlocked != NULL)
  1879. {
  1880. ecoUnlocked.vSetup(pState->prgnUnlocked, *(ERECTL*)prclSrc);
  1881. if (ecoUnlocked.erclExclude().bEmpty())
  1882. return; // ======>
  1883. pcoUnlocked = &ecoUnlocked;
  1884. }
  1885. // Mark the source surface to indicate that it shouldn't be cached,
  1886. // as it's pretty much guaranteed that we won't be blting the bitmap
  1887. // with exactly the same contents again.
  1888. //
  1889. // Note that this has to be in addition to any BMF_DONTCACHE flag
  1890. // that might have been set, as the TShare driver ignores the
  1891. // BMF_DONTCACHE flag.
  1892. psoSrc->iUniq = 0;
  1893. ASSERTGDI((pState->psoScreen->iType == pState->iOriginalType) &&
  1894. (SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen)->flags() == pState->flOriginalSurfFlags),
  1895. "Writing to screen without restoring orignal surface settings.");
  1896. OFFCOPYBITS(&gptlZero,
  1897. pState->psoScreen,
  1898. pOffSrc,
  1899. psoSrc,
  1900. pcoUnlocked,
  1901. NULL,
  1902. prclSrc,
  1903. (POINTL*) prclSrc);
  1904. }
  1905. /******************************Public*Routine******************************\
  1906. * VOID vSpDrawCursor
  1907. *
  1908. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1909. * Wrote it.
  1910. \**************************************************************************/
  1911. VOID vSpDrawCursor(
  1912. SPRITE* pSprite,
  1913. POINTL* pOffComposite,
  1914. SURFOBJ* psoComposite,
  1915. RECTL* prclEnum,
  1916. POINTL* pptlSrc)
  1917. {
  1918. SPRITESTATE* pState;
  1919. POINTL ptlSrc;
  1920. SURFOBJ* psoShape;
  1921. POINTL* pOffShape;
  1922. XLATEOBJ* pxlo;
  1923. // A NULL mask means that the shape couldn't be allocated:
  1924. if (pSprite->psoMask == NULL)
  1925. return;
  1926. pState = pSprite->pState;
  1927. EXLATEOBJ xloMono;
  1928. XEPALOBJ palMono(ppalMono);
  1929. XEPALOBJ palScreen(SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen)->ppal());
  1930. XEPALOBJ palDefault(ppalDefault);
  1931. // The XLATEOBJ should always be in the cache, so this should be pretty
  1932. // cheap most of the time:
  1933. if (xloMono.bInitXlateObj(NULL, DC_ICM_OFF, palMono, palScreen, palDefault,
  1934. palDefault, 0, 0xffffff, 0))
  1935. {
  1936. OFFBITBLT(pOffComposite, psoComposite, &gptlZero, pSprite->psoMask,
  1937. NULL, NULL, xloMono.pxlo(), prclEnum, pptlSrc, NULL,
  1938. NULL, NULL, 0x8888); // SRCAND
  1939. if (pSprite->psoShape == NULL)
  1940. {
  1941. ptlSrc.x = pptlSrc->x;
  1942. ptlSrc.y = pptlSrc->y + (pSprite->psoMask->sizlBitmap.cy >> 1);
  1943. psoShape = pSprite->psoMask;
  1944. pOffShape = &gptlZero;
  1945. pxlo = xloMono.pxlo();
  1946. }
  1947. else
  1948. {
  1949. ptlSrc.x = pptlSrc->x;
  1950. ptlSrc.y = pptlSrc->y;
  1951. psoShape = pSprite->psoShape;
  1952. pOffShape = &pSprite->OffShape;
  1953. pxlo = NULL;
  1954. }
  1955. OFFBITBLT(pOffComposite, psoComposite, pOffShape, psoShape, NULL,
  1956. NULL, pxlo, prclEnum, &ptlSrc, NULL, NULL, NULL,
  1957. 0x6666); // SRCINVERT
  1958. }
  1959. }
  1960. /******************************Public*Routine******************************\
  1961. * VOID vSpComposite
  1962. *
  1963. * Draws the specified sprite into the composition buffer.
  1964. *
  1965. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  1966. * Wrote it.
  1967. \**************************************************************************/
  1968. VOID vSpComposite(
  1969. SPRITE* pSprite,
  1970. POINTL* pOffComposite,
  1971. SURFOBJ* psoComposite,
  1972. RECTL* prclEnum)
  1973. {
  1974. SPRITESTATE* pState;
  1975. POINTL ptlSrc;
  1976. CLIPOBJ* pco;
  1977. DWORD dwShape;
  1978. ECLIPOBJ ecoClip;
  1979. CLIPOBJ* pcoClip;
  1980. SURFOBJ* psoNull = NULL;
  1981. // First, calculate the clipping:
  1982. pcoClip = NULL;
  1983. if (pSprite->prgnClip != NULL)
  1984. {
  1985. pcoClip = &ecoClip;
  1986. ecoClip.vSetup(pSprite->prgnClip, *((ERECTL*) prclEnum));
  1987. if ((ecoClip.rclBounds.left >= ecoClip.rclBounds.right) ||
  1988. (ecoClip.rclBounds.top >= ecoClip.rclBounds.bottom))
  1989. {
  1990. // It's completely clipped, so we're outta here:
  1991. return;
  1992. }
  1993. }
  1994. pState = pSprite->pState;
  1995. ASSERTGDI(pState->bInsideDriverCall, "Must have sprite lock");
  1996. dwShape = pSprite->dwShape;
  1997. if (pSprite->fl & SPRITE_FLAG_EFFECTIVELY_OPAQUE)
  1998. dwShape = ULW_OPAQUE;
  1999. ptlSrc.x = pSprite->rclSrc.left + (prclEnum->left - pSprite->ptlDst.x);
  2000. ptlSrc.y = pSprite->rclSrc.top + (prclEnum->top - pSprite->ptlDst.y);
  2001. XEPALOBJ palScreen(SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen)->ppal());
  2002. XEPALOBJ palSprite(pSprite->ppalShape);
  2003. XEPALOBJ palDefault(ppalDefault);
  2004. XEPALOBJ palRGB(gppalRGB);
  2005. EXLATEOBJ xloSpriteToDst;
  2006. // If the current color depth is the same as the color depth in which
  2007. // the sprite was originally created, we don't need an XLATEOBJ.
  2008. // Otherwise, create one now:
  2009. if (((pSprite->iModeFormat == pState->iModeFormat) &&
  2010. (pSprite->flModeMasks == pState->flModeMasks)) ||
  2011. (xloSpriteToDst.bInitXlateObj(NULL, DC_ICM_OFF, palSprite, palScreen,
  2012. palDefault, palDefault, 0, 0, 0)))
  2013. {
  2014. if (dwShape != ULW_ALPHA)
  2015. {
  2016. if (dwShape == ULW_OPAQUE)
  2017. {
  2018. if (pSprite->psoShape)
  2019. {
  2020. OFFCOPYBITS(pOffComposite,
  2021. psoComposite,
  2022. &pSprite->OffShape,
  2023. pSprite->psoShape,
  2024. pcoClip,
  2025. xloSpriteToDst.pxlo(),
  2026. prclEnum,
  2027. &ptlSrc);
  2028. }
  2029. }
  2030. else if (dwShape == ULW_COLORKEY)
  2031. {
  2032. if (pSprite->psoShape)
  2033. {
  2034. ERECTL rclSrc(ptlSrc.x,
  2035. ptlSrc.y,
  2036. ptlSrc.x + (prclEnum->right - prclEnum->left),
  2037. ptlSrc.y + (prclEnum->bottom - prclEnum->top));
  2038. OffTransparentBlt(PPFNDIRECT(psoComposite, TransparentBlt),
  2039. pOffComposite,
  2040. psoComposite,
  2041. &pSprite->OffShape,
  2042. pSprite->psoShape,
  2043. pcoClip,
  2044. xloSpriteToDst.pxlo(),
  2045. prclEnum,
  2046. &rclSrc,
  2047. pSprite->iTransparent,
  2048. 0);
  2049. }
  2050. }
  2051. else if (dwShape == ULW_CURSOR)
  2052. {
  2053. vSpDrawCursor(pSprite,
  2054. pOffComposite,
  2055. psoComposite,
  2056. prclEnum,
  2057. &ptlSrc);
  2058. }
  2059. else
  2060. {
  2061. ASSERTGDI(dwShape == ULW_DRAGRECT, "Unexpected shape");
  2062. PDEVOBJ po(pState->hdev);
  2063. OFFBITBLT(pOffComposite, psoComposite, NULL, psoNull, NULL, NULL,
  2064. NULL, prclEnum, NULL, NULL, po.pbo(), &gptlZero,
  2065. 0x5a5a);
  2066. }
  2067. }
  2068. else
  2069. {
  2070. ASSERTGDI(dwShape == ULW_ALPHA, "Unexpected case");
  2071. if (pSprite->psoShape)
  2072. {
  2073. EBLENDOBJ eBlendObj;
  2074. EXLATEOBJ xloSpriteTo32;
  2075. EXLATEOBJ xloScreenTo32;
  2076. EXLATEOBJ xlo32ToScreen;
  2077. ERECTL rclSrc(ptlSrc.x,
  2078. ptlSrc.y,
  2079. ptlSrc.x + (prclEnum->right - prclEnum->left),
  2080. ptlSrc.y + (prclEnum->bottom - prclEnum->top));
  2081. if ((xloSpriteTo32.bInitXlateObj(NULL, DC_ICM_OFF, palSprite, palRGB,
  2082. palDefault, palDefault, 0, 0, 0)) &&
  2083. (xloScreenTo32.bInitXlateObj(NULL, DC_ICM_OFF, palScreen, palRGB,
  2084. palDefault, palDefault, 0, 0, 0)) &&
  2085. (xlo32ToScreen.bInitXlateObj(NULL, DC_ICM_OFF, palRGB, palScreen,
  2086. palDefault, palDefault, 0, 0, 0)))
  2087. {
  2088. eBlendObj.BlendFunction = pSprite->BlendFunction;
  2089. eBlendObj.pxloSrcTo32 = xloSpriteTo32.pxlo();
  2090. eBlendObj.pxloDstTo32 = xloScreenTo32.pxlo();
  2091. eBlendObj.pxlo32ToDst = xlo32ToScreen.pxlo();
  2092. OffAlphaBlend(PPFNDIRECT(psoComposite, AlphaBlend),
  2093. pOffComposite,
  2094. psoComposite,
  2095. &pSprite->OffShape,
  2096. pSprite->psoShape,
  2097. pcoClip,
  2098. xloSpriteToDst.pxlo(),
  2099. prclEnum,
  2100. &rclSrc,
  2101. &eBlendObj);
  2102. }
  2103. }
  2104. }
  2105. }
  2106. }
  2107. /******************************Public*Routine******************************\
  2108. * SURFOBJ* psoSpGetComposite
  2109. *
  2110. * Returns a surface to be used for compositing.
  2111. *
  2112. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2113. * Wrote it.
  2114. \**************************************************************************/
  2115. SURFOBJ* psoSpGetComposite(
  2116. SPRITESTATE* pState,
  2117. RECTL* prcl)
  2118. {
  2119. SURFOBJ* psoComposite;
  2120. LONG cxMax;
  2121. LONG cyMax;
  2122. LONG cMaxArea;
  2123. LONG cx;
  2124. LONG cy;
  2125. LONG cArea;
  2126. BOOL bWantSystemMemory;
  2127. SPRITE* pSprite;
  2128. SPRITE* pBiggest;
  2129. psoComposite = pState->psoComposite;
  2130. if ((psoComposite == NULL) ||
  2131. (psoComposite->sizlBitmap.cx < (prcl->right - prcl->left)) ||
  2132. (psoComposite->sizlBitmap.cy < (prcl->bottom - prcl->top)))
  2133. {
  2134. vSpDeleteSurface(psoComposite); // Handles NULL case
  2135. cMaxArea = 0;
  2136. cxMax = 0;
  2137. cyMax = 0;
  2138. // Find the minimum dimensions needed to accomodate every sprite:
  2139. for (pSprite = pState->pListZ;
  2140. pSprite != NULL;
  2141. pSprite = pSprite->pNextZ)
  2142. {
  2143. cx = pSprite->rclSprite.right - pSprite->rclSprite.left;
  2144. if (cx > cxMax)
  2145. cxMax = cx;
  2146. cy = pSprite->rclSprite.bottom - pSprite->rclSprite.top;
  2147. if (cy > cyMax)
  2148. cyMax = cy;
  2149. cArea = cx * cy;
  2150. if (cArea > cMaxArea)
  2151. {
  2152. cMaxArea = cArea;
  2153. pBiggest = pSprite;
  2154. }
  2155. }
  2156. ASSERTGDI((cxMax > 0) && (cyMax > 0), "Expected a non-zero sprite");
  2157. bWantSystemMemory = FALSE;
  2158. if (pBiggest->dwShape == ULW_ALPHA)
  2159. {
  2160. PDEVOBJ po(pState->hdev);
  2161. if (pBiggest->BlendFunction.AlphaFormat & AC_SRC_ALPHA)
  2162. {
  2163. if (!(po.flAccelerated() & ACCELERATED_PIXEL_ALPHA))
  2164. {
  2165. bWantSystemMemory = TRUE;
  2166. }
  2167. }
  2168. else
  2169. {
  2170. if (!(po.flAccelerated() & ACCELERATED_CONSTANT_ALPHA))
  2171. {
  2172. bWantSystemMemory = TRUE;
  2173. }
  2174. }
  2175. }
  2176. // The compositing surface should always be in video-memory, unless
  2177. // there is a big alpha sprite somewhere, and the hardware doesn't
  2178. // accelerate alpha:
  2179. psoComposite = psoSpCreateSurface(pState,
  2180. 0,
  2181. cxMax,
  2182. cyMax,
  2183. bWantSystemMemory);
  2184. #if DEBUG_SPRITES
  2185. KdPrint(("psoComposite: %p\n", psoComposite));
  2186. #endif
  2187. pState->psoComposite = psoComposite;
  2188. // Mark the surface as uncacheable, so that we won't pollute the
  2189. // cache of the TShare driver, and the like:
  2190. if (psoComposite != NULL)
  2191. {
  2192. psoComposite->fjBitmap |= BMF_DONTCACHE;
  2193. // BMF_SPRITE appears to be unused. We are temporarily removing
  2194. // support to see if 3DLabs complains.
  2195. // psoComposite->fjBitmap |= BMF_SPRITE;
  2196. }
  2197. }
  2198. return(psoComposite);
  2199. }
  2200. /******************************Public*Routine******************************\
  2201. * VOID vSpRedrawArea
  2202. *
  2203. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2204. * Wrote it.
  2205. \**************************************************************************/
  2206. VOID vSpRedrawArea(
  2207. SPRITESTATE* pState,
  2208. RECTL* prclBounds,
  2209. BOOL bMustRedraw = FALSE)
  2210. {
  2211. SPRITE* pSprite;
  2212. RECTL rclEnum;
  2213. SURFOBJ* psoComposite;
  2214. POINTL OffComposite;
  2215. BOOL bMore;
  2216. BOOL hHasOpaqueLayer;
  2217. PDEVOBJ po(pState->hdev);
  2218. if (po.bDisabled())
  2219. return;
  2220. ASSERTGDI(pState->bInsideDriverCall, "Must have sprite lock");
  2221. ENUMAREAS Enum(pState, prclBounds);
  2222. do {
  2223. bMore = Enum.bEnum(&pSprite, &rclEnum);
  2224. ASSERTGDI((rclEnum.left >= pState->rclScreen.left) &&
  2225. (rclEnum.top >= pState->rclScreen.top) &&
  2226. (rclEnum.right <= pState->rclScreen.right) &&
  2227. (rclEnum.bottom <= pState->rclScreen.bottom),
  2228. "Enumerated rectangle exceeds screen bounds");
  2229. if (pSprite != NULL)
  2230. {
  2231. // We always draw bottom-to-top, but we don't have to
  2232. // bother drawing any layers that are below the top-most
  2233. // opaque layer:
  2234. hHasOpaqueLayer = Enum.bAdvanceToTopMostOpaqueLayer(&pSprite);
  2235. // If something was drawn under this layer region, and
  2236. // there was any opaque layer, we can early-out because
  2237. // we know we won't have to update the screen:
  2238. if ((!hHasOpaqueLayer) || (bMustRedraw))
  2239. {
  2240. // Create the compositing surface:
  2241. psoComposite = psoSpGetComposite(pState, &rclEnum);
  2242. if (psoComposite == NULL)
  2243. return; // ======>
  2244. // Set the composite buffer's origin for ease of use:
  2245. OffComposite.x = -rclEnum.left;
  2246. OffComposite.y = -rclEnum.top;
  2247. // Okay, we have to do things the slow way. First, copy
  2248. // the underlay to the composite buffer:
  2249. OFFCOPYBITS(&OffComposite,
  2250. psoComposite,
  2251. &pSprite->OffUnderlay,
  2252. pSprite->psoUnderlay,
  2253. NULL,
  2254. NULL,
  2255. &rclEnum,
  2256. (POINTL*) &rclEnum);
  2257. // Now composite each sprite:
  2258. do {
  2259. vSpComposite(pSprite,
  2260. &OffComposite,
  2261. psoComposite,
  2262. &rclEnum);
  2263. } while (Enum.bEnumLayers(&pSprite));
  2264. // Now copy the final composited result back to the screen:
  2265. vSpWriteToScreen(pState,
  2266. &OffComposite,
  2267. psoComposite,
  2268. &rclEnum);
  2269. }
  2270. }
  2271. } while (bMore);
  2272. }
  2273. /******************************Public*Routine******************************\
  2274. * SPRITE* pSpFindInZ
  2275. *
  2276. * Finds the next sprite in the list that intersects with the specified
  2277. * rectangle.
  2278. *
  2279. * This function's entire raison d'etre is for speed.
  2280. *
  2281. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2282. * Wrote it.
  2283. \**************************************************************************/
  2284. SPRITE* FASTCALL pSpFindInZ(
  2285. SPRITE* pSprite,
  2286. RECTL* prcl)
  2287. {
  2288. LONG xLeft = prcl->left;
  2289. LONG yTop = prcl->top;
  2290. LONG xRight = prcl->right;
  2291. LONG yBottom = prcl->bottom;
  2292. while (pSprite != NULL)
  2293. {
  2294. if ((pSprite->rclSprite.left < xRight) &&
  2295. (pSprite->rclSprite.top < yBottom) &&
  2296. (pSprite->rclSprite.right > xLeft) &&
  2297. (pSprite->rclSprite.bottom > yTop))
  2298. {
  2299. return(pSprite);
  2300. }
  2301. pSprite = pSprite->pNextZ;
  2302. }
  2303. return(pSprite);
  2304. }
  2305. /******************************Public*Routine******************************\
  2306. * VOID vSpRedrawSprite
  2307. *
  2308. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2309. * Wrote it.
  2310. \**************************************************************************/
  2311. VOID vSpRedrawSprite(
  2312. SPRITE* pSprite)
  2313. {
  2314. GDIFunctionID(vSpRedrawSprite);
  2315. SPRITESTATE* pState;
  2316. SURFOBJ* psoComposite;
  2317. POINTL OffComposite;
  2318. SPRITE* pIntersect;
  2319. RECTL rclIntersect;
  2320. pState = pSprite->pState;
  2321. // There's nothing to redraw if we're full-screen:
  2322. PDEVOBJ po(pState->hdev);
  2323. if (po.bDisabled())
  2324. return;
  2325. ASSERTGDI(pState->bInsideDriverCall,
  2326. "SPRITELOCK should be held");
  2327. if (pSprite->fl & SPRITE_FLAG_VISIBLE)
  2328. {
  2329. ASSERTGDI((pSprite->rclSprite.left < pSprite->rclSprite.right) &&
  2330. (pSprite->rclSprite.top < pSprite->rclSprite.bottom),
  2331. "Badly ordered rclSprite");
  2332. psoComposite = psoSpGetComposite(pState, &pSprite->rclSprite);
  2333. if (psoComposite == NULL)
  2334. return;
  2335. // Set the composite buffer's origin for ease of use:
  2336. OffComposite.x = -pSprite->rclSprite.left;
  2337. OffComposite.y = -pSprite->rclSprite.top;
  2338. // First, copy the underlay to the composite buffer:
  2339. OFFCOPYBITS(&OffComposite,
  2340. psoComposite,
  2341. &pSprite->OffUnderlay,
  2342. pSprite->psoUnderlay,
  2343. NULL,
  2344. NULL,
  2345. &pSprite->rclSprite,
  2346. (POINTL*) &pSprite->rclSprite);
  2347. // Now composite each sprite:
  2348. pIntersect = pSpFindInZ(pState->pListZ, &pSprite->rclSprite);
  2349. while (pIntersect != NULL)
  2350. {
  2351. if (bIntersect(&pIntersect->rclSprite,
  2352. &pSprite->rclSprite,
  2353. &rclIntersect))
  2354. {
  2355. vSpComposite(pIntersect,
  2356. &OffComposite,
  2357. psoComposite,
  2358. &rclIntersect);
  2359. }
  2360. pIntersect = pSpFindInZ(pIntersect->pNextZ, &pSprite->rclSprite);
  2361. }
  2362. // Now copy the final composited result back to the screen:
  2363. vSpWriteToScreen(pState,
  2364. &OffComposite,
  2365. psoComposite,
  2366. &pSprite->rclSprite);
  2367. // set time stamp
  2368. pSprite->ulTimeStamp = NtGetTickCount();
  2369. }
  2370. }
  2371. /******************************Public*Routine******************************\
  2372. * ULONG cSpSubtract
  2373. *
  2374. * Simple little routine that returns back the list of rectangles that
  2375. * make up the area defined by 'prclA' minus 'prclB'.
  2376. *
  2377. * Returns the number and values of the resulting rectangles, which will
  2378. * be no more than four.
  2379. *
  2380. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2381. * Wrote it.
  2382. \**************************************************************************/
  2383. ULONG FASTCALL cSpSubtract(
  2384. CONST RECTL* prclA, // Computes A - B
  2385. CONST RECTL* prclB,
  2386. RECTL* arcl)
  2387. {
  2388. RECTL rcl;
  2389. RECTL* prcl;
  2390. prcl = arcl;
  2391. rcl.left = LONG_MIN;
  2392. rcl.top = LONG_MIN;
  2393. rcl.right = LONG_MAX;
  2394. rcl.bottom = prclB->top;
  2395. if (bIntersect(&rcl, prclA, prcl))
  2396. prcl++;
  2397. rcl.top = prclB->top;
  2398. rcl.right = prclB->left;
  2399. rcl.bottom = prclB->bottom;
  2400. if (bIntersect(&rcl, prclA, prcl))
  2401. prcl++;
  2402. rcl.left = prclB->right;
  2403. rcl.right = LONG_MAX;
  2404. if (bIntersect(&rcl, prclA, prcl))
  2405. prcl++;
  2406. rcl.left = LONG_MIN;
  2407. rcl.top = prclB->bottom;
  2408. rcl.bottom = LONG_MAX;
  2409. if (bIntersect(&rcl, prclA, prcl))
  2410. prcl++;
  2411. return((ULONG) (prcl - arcl));
  2412. }
  2413. /******************************Public*Routine******************************\
  2414. * VOID vSpRedrawUncoveredArea
  2415. *
  2416. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2417. * Wrote it.
  2418. \**************************************************************************/
  2419. VOID vSpRedrawUncoveredArea(
  2420. SPRITE* pSprite,
  2421. RECTL* prclNew)
  2422. {
  2423. SPRITESTATE* pState;
  2424. RECTL arclUncovered[4];
  2425. RECTL rclTmp;
  2426. ULONG crclUncovered;
  2427. SURFOBJ* psoComposite;
  2428. POINTL OffComposite;
  2429. SPRITE* pTmp;
  2430. BOOL bHit;
  2431. ULONG i;
  2432. ULONG j;
  2433. pState = pSprite->pState;
  2434. // There's nothing to redraw if we're full-screen:
  2435. PDEVOBJ po(pState->hdev);
  2436. if (po.bDisabled())
  2437. return;
  2438. ASSERTGDI(pState->bInsideDriverCall,
  2439. "SPRITELOCK should be held");
  2440. crclUncovered = cSpSubtract(&pSprite->rclSprite, prclNew, &arclUncovered[0]);
  2441. if (crclUncovered)
  2442. {
  2443. bHit = FALSE;
  2444. psoComposite = psoSpGetComposite(pState, &pSprite->rclSprite);
  2445. if (psoComposite == NULL)
  2446. return;
  2447. // Set the composite buffer's origin for ease of use:
  2448. OffComposite.x = -pSprite->rclSprite.left;
  2449. OffComposite.y = -pSprite->rclSprite.top;
  2450. pTmp = pSpFindInZ(pState->pListZ, &pSprite->rclSprite);
  2451. while (pTmp != NULL)
  2452. {
  2453. if (pTmp != pSprite)
  2454. {
  2455. for (i = 0; i < crclUncovered; i++)
  2456. {
  2457. if (bIntersect(&arclUncovered[i], &pTmp->rclSprite, &rclTmp))
  2458. {
  2459. if (!bHit)
  2460. {
  2461. for (j = 0; j < crclUncovered; j++)
  2462. {
  2463. OFFCOPYBITS(&OffComposite,
  2464. psoComposite,
  2465. &pSprite->OffUnderlay,
  2466. pSprite->psoUnderlay,
  2467. NULL,
  2468. NULL,
  2469. &arclUncovered[j],
  2470. (POINTL*) &arclUncovered[j]);
  2471. }
  2472. bHit = TRUE;
  2473. }
  2474. vSpComposite(pTmp,
  2475. &OffComposite,
  2476. psoComposite,
  2477. &rclTmp);
  2478. }
  2479. }
  2480. }
  2481. pTmp = pSpFindInZ(pTmp->pNextZ, &pSprite->rclSprite);
  2482. }
  2483. for (i = 0; i < crclUncovered; i++)
  2484. {
  2485. if (bHit)
  2486. {
  2487. vSpWriteToScreen(pState,
  2488. &OffComposite,
  2489. psoComposite,
  2490. &arclUncovered[i]);
  2491. }
  2492. else
  2493. {
  2494. vSpWriteToScreen(pState,
  2495. &pSprite->OffUnderlay,
  2496. pSprite->psoUnderlay,
  2497. &arclUncovered[i]);
  2498. }
  2499. }
  2500. }
  2501. }
  2502. /******************************Public*Routine******************************\
  2503. * VOID vSpSmallUnderlayCopy
  2504. *
  2505. * Updates the underlay bits of a sprite without forcing a re-compute
  2506. * of the sprite-range data structure.
  2507. *
  2508. * Copies a rectangle from the screen to the specified underlay surface.
  2509. * We update the underlay surface by first copying the entire rectangle
  2510. * straight from the frame buffer (which may include bits of other sprites),
  2511. * and then looping through the sprite list copying their underlays whereever
  2512. * they intersect.
  2513. *
  2514. * Note that if multiple sprites overlap, we'll be overwriting portions of
  2515. * the sprite many times. Overdrawing pixels like this is always inefficient,
  2516. * but if the sprite size is small it won't be too bad. On the other hand,
  2517. * if there are many sprites, the computation of the sprite range structure
  2518. * will be *very* expensive.
  2519. *
  2520. * So for small sprites, it's often faster to over-draw pixels than to
  2521. * re-compute the sprite range structure.
  2522. *
  2523. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2524. * Wrote it.
  2525. \**************************************************************************/
  2526. // The 'SMALL_SPRITE_DIMENSION' is the maximum pixel dimension for which
  2527. // a sprite move will be done without recomputing the sprite ranges.
  2528. #define SMALL_SPRITE_DIMENSION 128
  2529. VOID vSpSmallUnderlayCopy(
  2530. SPRITE* pSprite,
  2531. POINTL* pOffDst,
  2532. SURFOBJ* psoDst,
  2533. POINTL* pOffSrc,
  2534. SURFOBJ* psoSrc,
  2535. LONG dx,
  2536. LONG dy,
  2537. RECTL* prclNew,
  2538. RECTL* prclOld)
  2539. {
  2540. SPRITESTATE* pState;
  2541. RECTL rclSrc;
  2542. RECTL rclDst;
  2543. ULONG crcl;
  2544. RECTL arcl[4];
  2545. ULONG i;
  2546. SPRITE* pTmp;
  2547. RECTL rclTmp;
  2548. pState = pSprite->pState;
  2549. // There's nothing to redraw if we're full-screen:
  2550. PDEVOBJ po(pState->hdev);
  2551. if (po.bDisabled())
  2552. return;
  2553. ASSERTGDI(pState->bInsideDriverCall,
  2554. "SPRITELOCK should be held");
  2555. if (bIntersect(prclOld, prclNew, &rclDst))
  2556. {
  2557. rclSrc.left = dx + rclDst.left;
  2558. rclSrc.right = dx + rclDst.right;
  2559. rclSrc.top = dy + rclDst.top;
  2560. rclSrc.bottom = dy + rclDst.bottom;
  2561. OFFCOPYBITS(pOffDst,
  2562. psoDst,
  2563. pOffSrc,
  2564. psoSrc,
  2565. NULL,
  2566. NULL,
  2567. &rclDst,
  2568. (POINTL*) &rclSrc);
  2569. }
  2570. crcl = cSpSubtract(prclNew, prclOld, arcl);
  2571. ASSERTGDI(crcl != 0, "Shouldn't have an empty source");
  2572. i = 0;
  2573. do {
  2574. vSpReadFromScreen(pState, pOffDst, psoDst, &arcl[i]);
  2575. } while (++i != crcl);
  2576. pTmp = pSpFindInZ(pState->pListZ, prclNew);
  2577. while (pTmp != NULL)
  2578. {
  2579. if (pTmp != pSprite)
  2580. {
  2581. i = 0;
  2582. do {
  2583. if (bIntersect(&arcl[i], &pTmp->rclSprite, &rclTmp))
  2584. {
  2585. OFFCOPYBITS(pOffDst,
  2586. psoDst,
  2587. &pTmp->OffUnderlay,
  2588. pTmp->psoUnderlay,
  2589. NULL,
  2590. NULL,
  2591. &rclTmp,
  2592. (POINTL*) &rclTmp);
  2593. }
  2594. } while (++i != crcl);
  2595. }
  2596. pTmp = pSpFindInZ(pTmp->pNextZ, prclNew);
  2597. }
  2598. }
  2599. /******************************Public*Routine******************************\
  2600. * VOID vSpBigUnderlayCopy
  2601. *
  2602. * Reads a (future underlay) buffer from the screen, automatically excluding
  2603. * any sprites that may be in the way.
  2604. *
  2605. * This routine will be slow if the area is small, there are a large number
  2606. * of sprites, and ENUMAREAS forces the sprite ranges to be re-calculated;
  2607. * it will be fast if the buffer to be read is large.
  2608. *
  2609. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2610. * Wrote it.
  2611. \**************************************************************************/
  2612. VOID vSpBigUnderlayCopy(
  2613. SPRITESTATE* pState,
  2614. POINTL* pOffUnderlay,
  2615. SURFOBJ* psoUnderlay,
  2616. RECTL* prcl)
  2617. {
  2618. SPRITE* pSprite;
  2619. RECTL rclEnum;
  2620. BOOL bMore;
  2621. // There's nothing to redraw if we're full-screen:
  2622. PDEVOBJ po(pState->hdev);
  2623. if (po.bDisabled())
  2624. return;
  2625. ASSERTGDI(pState->bInsideDriverCall,
  2626. "SPRITELOCK should be held");
  2627. ENUMAREAS Enum(pState, prcl);
  2628. do {
  2629. bMore = Enum.bEnum(&pSprite, &rclEnum);
  2630. if (pSprite == NULL)
  2631. {
  2632. vSpReadFromScreen(pState, pOffUnderlay, psoUnderlay, &rclEnum);
  2633. }
  2634. else
  2635. {
  2636. OFFCOPYBITS(pOffUnderlay,
  2637. psoUnderlay,
  2638. &pSprite->OffUnderlay,
  2639. pSprite->psoUnderlay,
  2640. NULL,
  2641. NULL,
  2642. &rclEnum,
  2643. (POINTL*) &rclEnum);
  2644. }
  2645. } while (bMore);
  2646. }
  2647. /******************************Public*Routine******************************\
  2648. * VOID vSpUpdateLockedScreenAreas
  2649. *
  2650. * When a screen-to-screen blt occurs, the screen-to-screen blt may occur
  2651. * under an area of the screen that is both locked by DirectDraw and covered
  2652. * by a sprite. Normally, we never update the locked area under the sprite,
  2653. * but in this case we do, to reflect the moved contents.
  2654. *
  2655. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2656. * Wrote it.
  2657. \**************************************************************************/
  2658. VOID vSpUpdateLockedScreenAreas(
  2659. SPRITESTATE* pState,
  2660. POINTL* pOffDst,
  2661. RECTL* prclDst,
  2662. CLIPOBJ* pco,
  2663. BOOL bReadFromScreen)
  2664. {
  2665. SPRITE* pSprite;
  2666. BOOL bMore;
  2667. RECTL rclEnum;
  2668. RECTL rclArea;
  2669. REGION* prgnIntersect;
  2670. ECLIPOBJ ecoIntersect;
  2671. RGNOBJ* proClip;
  2672. RGNMEMOBJTMP rmoIntersect;
  2673. RGNMEMOBJTMP rmoScreen;
  2674. ASSERTGDI(pState->prgnUnlocked != NULL,
  2675. "Should really be called only when a DirectDraw lock is extant");
  2676. PDEVOBJ po(pState->hdev);
  2677. SPRITELOCK slock(po);
  2678. prgnIntersect = NULL;
  2679. if (rmoIntersect.bValid() &&
  2680. rmoScreen.bValid() &&
  2681. bIntersect(prclDst, &pState->rclScreen, &rclArea))
  2682. {
  2683. ENUMAREAS Enum(pState, &rclArea);
  2684. do {
  2685. bMore = Enum.bEnum(&pSprite, &rclEnum);
  2686. if (pSprite != NULL)
  2687. {
  2688. if (prgnIntersect == NULL)
  2689. {
  2690. proClip = (ECLIPOBJ*) pco;
  2691. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  2692. {
  2693. rmoScreen.vSet(&pState->rclScreen);
  2694. proClip = &rmoScreen;
  2695. }
  2696. // Intersect the clip object supplied by the drawing
  2697. // routine with the not of region representing the
  2698. // 'unlocked' portions of the screen.
  2699. RGNOBJ roUnlocked(pState->prgnUnlocked);
  2700. if (!rmoIntersect.bMerge(*proClip,
  2701. roUnlocked,
  2702. gafjRgnOp[RGN_DIFF]))
  2703. {
  2704. rmoIntersect.vSet();
  2705. }
  2706. prgnIntersect = rmoIntersect.prgnGet();
  2707. }
  2708. ecoIntersect.vSetup(prgnIntersect, *(ERECTL*) &rclEnum);
  2709. if (!ecoIntersect.erclExclude().bEmpty())
  2710. {
  2711. do {
  2712. if (bReadFromScreen)
  2713. {
  2714. OFFCOPYBITS(&pSprite->OffUnderlay,
  2715. pSprite->psoUnderlay,
  2716. pOffDst,
  2717. pState->psoScreen,
  2718. &ecoIntersect,
  2719. NULL,
  2720. &rclEnum,
  2721. (POINTL*) &rclEnum);
  2722. }
  2723. else
  2724. {
  2725. OFFCOPYBITS(pOffDst,
  2726. pState->psoScreen,
  2727. &pSprite->OffUnderlay,
  2728. pSprite->psoUnderlay,
  2729. &ecoIntersect,
  2730. NULL,
  2731. &rclEnum,
  2732. (POINTL*) &rclEnum);
  2733. }
  2734. } while ((bReadFromScreen) && (Enum.bEnumLayers(&pSprite)));
  2735. }
  2736. }
  2737. } while (bMore);
  2738. }
  2739. }
  2740. /******************************Public*Routine******************************\
  2741. * ENUMUNDERLAYS::ENUMUNDERLAYS
  2742. *
  2743. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2744. * Wrote it.
  2745. \**************************************************************************/
  2746. ENUMUNDERLAYS::ENUMUNDERLAYS(
  2747. SURFOBJ* pso,
  2748. CLIPOBJ* pco,
  2749. RECTL* prclDraw)
  2750. {
  2751. PDEVOBJ po(pso->hdev);
  2752. BOOL bRclNotEmpty = TRUE;
  2753. bDone = FALSE;
  2754. bSpriteTouched = FALSE;
  2755. bResetSurfFlag = FALSE;
  2756. pCurrentSprite = NULL;
  2757. pcoOriginal = pco;
  2758. psoOriginal = pso;
  2759. // This extra 'if' was added for GetPixel:
  2760. if (po.bValid())
  2761. {
  2762. pState = po.pSpriteState();
  2763. if ((pso == pState->psoScreen) && !(pState->bInsideDriverCall))
  2764. {
  2765. ASSERTGDI(!po.bDisabled(),
  2766. "Mustn't be called when PDEV disabled");
  2767. ASSERTGDI((pState->flOriginalSurfFlags & ~HOOK_FLAGS)
  2768. == (SURFOBJ_TO_SURFACE(pso)->SurfFlags & ~HOOK_FLAGS),
  2769. "SurfFlags was modified, but we're about to save over it!");
  2770. SURFOBJ_TO_SURFACE_NOT_NULL(pso)->flags(pState->flOriginalSurfFlags);
  2771. SURFOBJ_TO_SURFACE_NOT_NULL(pso)->iType(pState->iOriginalType);
  2772. pState->bInsideDriverCall = TRUE;
  2773. bResetSurfFlag = TRUE;
  2774. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  2775. {
  2776. rclBounds = *prclDraw;
  2777. pcoClip = &pState->coRectangular;
  2778. }
  2779. else
  2780. {
  2781. rclSaveBounds = pco->rclBounds;
  2782. bRclNotEmpty = bIntersect(prclDraw, &pco->rclBounds, &rclBounds);
  2783. pcoClip = pco;
  2784. }
  2785. // Find intersecting sprite if we have non-empty bounds;
  2786. // otherwise, leave pCurrentSprite = NULL.
  2787. if (bRclNotEmpty)
  2788. {
  2789. pCurrentSprite = pSpFindInZ(pState->pListZ, &rclBounds);
  2790. }
  2791. }
  2792. }
  2793. }
  2794. /******************************Public*Routine******************************\
  2795. * ENUMUNDERLAYS::bEnum
  2796. *
  2797. * This routine is a helper function for drawing primitives that handles
  2798. * the drawing of the primitive to various sprite underlay and screen
  2799. * surfaces. It takes the form of an enumeration function in order to
  2800. * return back the appropriate surface and clip objects that should be
  2801. * drawn on by the caller.
  2802. *
  2803. * Returns: TRUE if the caller should draw using the returned values;
  2804. * FALSE if no more drawing needs to be done.
  2805. *
  2806. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2807. * Wrote it.
  2808. \**************************************************************************/
  2809. BOOL ENUMUNDERLAYS::bEnum(
  2810. SURFOBJ** ppso,
  2811. POINTL* pOff,
  2812. CLIPOBJ** ppco)
  2813. {
  2814. RECTL rclTmp;
  2815. // We first draw to the underlay surfaces of any sprites that
  2816. // intersect with our area of interest. See if there is
  2817. // another sprite that intersects, and if so return that:
  2818. while (pCurrentSprite != NULL)
  2819. {
  2820. if (bIntersect(&pCurrentSprite->rclSprite, &rclBounds, &rclTmp))
  2821. {
  2822. ASSERTGDI(pcoClip->iDComplexity != DC_TRIVIAL,
  2823. "Expected non-trivial clipping when drawing to sprite");
  2824. bSpriteTouched = TRUE;
  2825. pcoClip->rclBounds = rclTmp;
  2826. *ppco = pcoClip;
  2827. *ppso = pCurrentSprite->psoUnderlay;
  2828. *pOff = pCurrentSprite->OffUnderlay;
  2829. pCurrentSprite = pCurrentSprite->pNextZ;
  2830. return(TRUE);
  2831. }
  2832. pCurrentSprite = pSpFindInZ(pCurrentSprite->pNextZ, &rclBounds);
  2833. }
  2834. if (!bDone)
  2835. {
  2836. if (!bSpriteTouched)
  2837. {
  2838. // No sprites intersected with the region of drawing, so we
  2839. // can simply return back the original clipping and surface
  2840. // object:
  2841. bDone = TRUE;
  2842. *ppco = pcoOriginal;
  2843. *ppso = psoOriginal;
  2844. pOff->x = 0;
  2845. pOff->y = 0;
  2846. return(TRUE);
  2847. }
  2848. // Okay, at this point we have work to do. We have to 'cut out'
  2849. // of the original clip objects any areas that were covered
  2850. // by the sprites.
  2851. if (!pState->bValidRange)
  2852. {
  2853. vSpComputeSpriteRanges(pState);
  2854. }
  2855. if (pcoClip->iDComplexity != DC_COMPLEX)
  2856. {
  2857. // Oh good, we can use our already-constructed complex region
  2858. // describing the uncovered parts of the screen.
  2859. //
  2860. // Use CLIP_FORCE to ensure that 'rclBounds' is always respected
  2861. // as the bounds, so that we don't revert to DC_TRIVIAL clipping
  2862. // when in fact the original call came in clipped:
  2863. pState->coTmp.vSetup(pState->prgnUncovered,
  2864. *((ERECTL*)&rclBounds),
  2865. CLIP_FORCE);
  2866. }
  2867. else
  2868. {
  2869. // Okay, we've got some work to do. We have to subtract each of
  2870. // the sprite rectangles from the drawing call's clip object.
  2871. RGNOBJ roUncovered(pState->prgnUncovered);
  2872. RGNOBJ roTmp(pState->prgnTmp);
  2873. // Find the intersection of the two regions. If the bMerge fails,
  2874. // we'll draw wrong, but we won't crash.
  2875. if (!roTmp.bMerge(*((XCLIPOBJ*)pcoClip), roUncovered, gafjRgnOp[RGN_AND]))
  2876. {
  2877. roTmp.vSet();
  2878. }
  2879. // Compute the resulting clip object:
  2880. pState->prgnTmp = roTmp.prgnGet();
  2881. pState->coTmp.vSetup(pState->prgnTmp,
  2882. *((ERECTL*)&rclBounds),
  2883. CLIP_FORCE);
  2884. }
  2885. // Note that this 'bIntersect' test handles the empty case for
  2886. // 'coTmp.rclBounds':
  2887. if (bIntersect(&pState->coTmp.rclBounds, &rclBounds))
  2888. {
  2889. ASSERTGDI((pState->prgnUnlocked != NULL) ||
  2890. (pState->coTmp.iDComplexity != DC_TRIVIAL),
  2891. "If sprite was touched, expect clipping on uncovered portion!");
  2892. bDone = TRUE;
  2893. *ppco = &pState->coTmp;
  2894. *ppso = psoOriginal;
  2895. pOff->x = 0;
  2896. pOff->y = 0;
  2897. return(TRUE);
  2898. }
  2899. }
  2900. // We're all done, update the screen underneath the sprites if need be:
  2901. if (bResetSurfFlag)
  2902. {
  2903. if (bSpriteTouched)
  2904. {
  2905. // One problem that is visible with sprites, particularly when
  2906. // using a software cursor, is that when drawing a single
  2907. // primitive, there is sometimes a noticeable temporal gap between
  2908. // the time that the area around the sprite is drawn, and the area
  2909. // underneath the sprite is updated.
  2910. //
  2911. // I used to update the area underneath the sprite before
  2912. // doing the drawing that occurs around the sprite, reasoning that
  2913. // people tend to be looking exactly at the cursor sprite and would
  2914. // benefit most from that area being updated as soon as possible,
  2915. // before the surrounding area.
  2916. //
  2917. // But I've changed my mind, and think the opposite is better.
  2918. // This is partly because drawing operations with complex clipping
  2919. // often need longer setup time than it does to update the sprite,
  2920. // so the time difference between the two is lessened if the
  2921. // sprite is updated *after* the complex clipped drawing is done.
  2922. //
  2923. // (I'll add that I also tried updating in chunks from top to
  2924. // bottom, but the resulting tearing was far worse.)
  2925. vSpRedrawArea(pState, &rclBounds);
  2926. }
  2927. ASSERTGDI((pState->flOriginalSurfFlags & ~HOOK_FLAGS)
  2928. == (SURFOBJ_TO_SURFACE(psoOriginal)->SurfFlags & ~HOOK_FLAGS),
  2929. "SurfFlags was modified, but we're about to restore over it!");
  2930. SURFOBJ_TO_SURFACE_NOT_NULL(psoOriginal)->flags(pState->flSpriteSurfFlags);
  2931. SURFOBJ_TO_SURFACE_NOT_NULL(psoOriginal)->iType(pState->iSpriteType);
  2932. pState->bInsideDriverCall = FALSE;
  2933. // This restores the original clip object's bounds if need be (or it
  2934. // overwrites 'coRectangular.rclBounds', which is also fine):
  2935. pcoClip->rclBounds = rclSaveBounds;
  2936. }
  2937. return(FALSE);
  2938. }
  2939. /******************************Public*Routine******************************\
  2940. * BOOL SpStrokePath
  2941. *
  2942. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2943. * Wrote it.
  2944. \**************************************************************************/
  2945. BOOL SpStrokePath(
  2946. SURFOBJ* pso,
  2947. PATHOBJ* ppo,
  2948. CLIPOBJ* pco,
  2949. XFORMOBJ* pxlo,
  2950. BRUSHOBJ* pbo,
  2951. POINTL* pptlBrush,
  2952. LINEATTRS* pla,
  2953. MIX mix)
  2954. {
  2955. BOOL bRet = TRUE;
  2956. BOOL bThis;
  2957. FLOAT_LONG elStyleState;
  2958. POINTL Offset;
  2959. ASSERTGDI(pco != NULL, "Drivers always expect non-NULL pco's for this call");
  2960. elStyleState = pla->elStyleState;
  2961. ENUMUNDERLAYS Enum(pso, pco, &pco->rclBounds);
  2962. while (Enum.bEnum(&pso, &Offset, &pco))
  2963. {
  2964. // We have to reset the style state every time we call StrokePath,
  2965. // otherwise it incorrectly accumulates. Also reset the path enumeration.
  2966. pla->elStyleState = elStyleState;
  2967. PATHOBJ_vEnumStart(ppo);
  2968. bThis = OffStrokePath(PPFNDIRECT(pso, StrokePath), &Offset, pso,
  2969. ppo, pco, pxlo, pbo, pptlBrush, pla, mix);
  2970. // Drivers can return TRUE, FALSE, or DDI_ERROR from this call. We
  2971. // should have caught any FALSE cases lower down, so permute them
  2972. // to failures should they have actually occurred:
  2973. if (!bThis)
  2974. bRet = DDI_ERROR;
  2975. }
  2976. return(bRet);
  2977. }
  2978. /******************************Public*Routine******************************\
  2979. * BOOL SpFillPath
  2980. *
  2981. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  2982. * Wrote it.
  2983. \**************************************************************************/
  2984. BOOL SpFillPath(
  2985. SURFOBJ* pso,
  2986. PATHOBJ* ppo,
  2987. CLIPOBJ* pco,
  2988. BRUSHOBJ* pbo,
  2989. POINTL* pptlBrush,
  2990. MIX mix,
  2991. FLONG flOptions)
  2992. {
  2993. BOOL bRet = TRUE;
  2994. BOOL bThis;
  2995. POINTL Offset;
  2996. ASSERTGDI(pco != NULL, "Drivers always expect non-NULL pco's for this call");
  2997. ENUMUNDERLAYS Enum(pso, pco, &pco->rclBounds);
  2998. while (Enum.bEnum(&pso, &Offset, &pco))
  2999. {
  3000. // Reset the path enumeration
  3001. PATHOBJ_vEnumStart(ppo);
  3002. bThis = OffFillPath(PPFNDIRECT(pso, FillPath), &Offset, pso, ppo, pco,
  3003. pbo, pptlBrush, mix, flOptions);
  3004. // Drivers can return TRUE, FALSE, or DDI_ERROR from this call. We
  3005. // should have caught any FALSE cases lower down, so permute them
  3006. // to failures should they have actually occurred:
  3007. if (!bThis)
  3008. bRet = DDI_ERROR;
  3009. }
  3010. return(bRet);
  3011. }
  3012. /******************************Public*Routine******************************\
  3013. * BOOL bSpBltScreenToScreen
  3014. *
  3015. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3016. * Wrote it.
  3017. \**************************************************************************/
  3018. BOOL bSpBltScreenToScreen(
  3019. SURFOBJ* pso,
  3020. SURFOBJ* psoIgnore,
  3021. SURFOBJ* psoMsk,
  3022. CLIPOBJ* pco,
  3023. XLATEOBJ* pxlo,
  3024. RECTL* prclDst,
  3025. POINTL* pptlSrc,
  3026. POINTL* pptlMsk,
  3027. BRUSHOBJ* pbo,
  3028. POINTL* pptlBrush,
  3029. ROP4 rop4)
  3030. {
  3031. SPRITESTATE* pState;
  3032. LONG dx;
  3033. LONG dy;
  3034. ULONG iDirection;
  3035. POINTL Offset;
  3036. RECTL rclIntersect;
  3037. RECTL rclSrc;
  3038. RECTL rclDst;
  3039. RECTL rclSubSrc;
  3040. RECTL rclSubDst;
  3041. POINTL ptlSubMsk;
  3042. POINTL ptlPreviousDst;
  3043. SPRITE* pSpriteDst;
  3044. SPRITE* pSpriteSrc;
  3045. SPRITE* pSpriteTmp;
  3046. SURFOBJ* psoSrc;
  3047. SURFOBJ* psoDst;
  3048. RECTL rclBounds;
  3049. BOOL bMore;
  3050. BOOL bSubMore;
  3051. POINTL* pOffDst;
  3052. POINTL* pOffSrc;
  3053. PDEVOBJ po(pso->hdev);
  3054. pState = po.pSpriteState();
  3055. // Restore the surface's original attributes.
  3056. SPRITELOCK slock(po);
  3057. dx = prclDst->left - pptlSrc->x;
  3058. dy = prclDst->top - pptlSrc->y;
  3059. if (dx > 0)
  3060. iDirection = (dy > 0) ? CD_LEFTUP : CD_LEFTDOWN;
  3061. else
  3062. iDirection = (dy > 0) ? CD_RIGHTUP : CD_RIGHTDOWN;
  3063. if (pco != NULL)
  3064. {
  3065. if (pco->iDComplexity == DC_TRIVIAL)
  3066. pco = NULL;
  3067. else
  3068. rclBounds = pco->rclBounds;
  3069. }
  3070. // If parts of the screen are locked by DirectDraw, update our underlay
  3071. // buffers for the portions covered by both the source rectangle and
  3072. // the destination rectangle and intersect with the locked portion of
  3073. // of the screen. (This case handles a screen-to-screen blt where
  3074. // a DirectDraw lock sits right in the middle of both.)
  3075. if (pState->prgnUnlocked != NULL)
  3076. {
  3077. rclSrc.left = prclDst->left - dx;
  3078. rclSrc.right = prclDst->right - dx;
  3079. rclSrc.top = prclDst->top - dy;
  3080. rclSrc.bottom = prclDst->bottom - dy;
  3081. if (bIntersect(prclDst, &rclSrc, &rclIntersect))
  3082. {
  3083. vSpUpdateLockedScreenAreas(pState, &gptlZero, &rclIntersect, pco, TRUE);
  3084. }
  3085. }
  3086. ENUMAREAS Enum(pState, prclDst, iDirection);
  3087. // Only check ENUMAREAS::bValid because of the nested ENUMAREAS call below
  3088. // (in the failure case, proceeding is bad because the nested call might
  3089. // succeed in recomputing the sprite ranges and leave us with bad
  3090. // pointers).
  3091. if (Enum.bValid())
  3092. {
  3093. do {
  3094. bMore = Enum.bEnum(&pSpriteDst, &rclDst);
  3095. rclSrc.left = rclDst.left - dx;
  3096. rclSrc.right = rclDst.right - dx;
  3097. rclSrc.top = rclDst.top - dy;
  3098. rclSrc.bottom = rclDst.bottom - dy;
  3099. // For rectangles that intersect multiple sprites, I had thought
  3100. // about simply composing the one overlay for that rectangle, and
  3101. // then copying that to the others. The problem I saw with that
  3102. // was that if that 'master' underlay is in video memory, but the
  3103. // rest are in system memory, that will actually be slower.
  3104. do {
  3105. if (pSpriteDst == NULL)
  3106. {
  3107. psoDst = pso;
  3108. pOffDst = &gptlZero;
  3109. }
  3110. else
  3111. {
  3112. psoDst = pSpriteDst->psoUnderlay;
  3113. pOffDst = &pSpriteDst->OffUnderlay;
  3114. }
  3115. ENUMAREAS SubEnum(pState, &rclSrc, iDirection);
  3116. do {
  3117. bSubMore = SubEnum.bEnum(&pSpriteSrc, &rclSubSrc);
  3118. // We have to be sure to use as the source the last layered
  3119. // underlay in the list, because we may be traversing
  3120. // through the same list to find the destination surfaces --
  3121. // and we don't want to modify our source before we've copied
  3122. // it to all the other surfaces! This bug took me an
  3123. // embarrassingly long time to fix, because it would only
  3124. // mis-draw when screen-to-screen blts occurred under
  3125. // actively moving sprites that overlayed each other.
  3126. while (SubEnum.bEnumLayers(&pSpriteTmp))
  3127. {
  3128. pSpriteSrc = pSpriteTmp;
  3129. }
  3130. if (pSpriteSrc == NULL)
  3131. {
  3132. psoSrc = pso;
  3133. pOffSrc = &gptlZero;
  3134. }
  3135. else
  3136. {
  3137. psoSrc = pSpriteSrc->psoUnderlay;
  3138. pOffSrc = &pSpriteSrc->OffUnderlay;
  3139. }
  3140. rclSubDst.left = rclSubSrc.left + dx;
  3141. rclSubDst.right = rclSubSrc.right + dx;
  3142. rclSubDst.top = rclSubSrc.top + dy;
  3143. rclSubDst.bottom = rclSubSrc.bottom + dy;
  3144. ASSERTGDI((rclSubDst.left >= pState->rclScreen.left) &&
  3145. (rclSubDst.top >= pState->rclScreen.top) &&
  3146. (rclSubDst.right <= pState->rclScreen.right) &&
  3147. (rclSubDst.bottom <= pState->rclScreen.bottom),
  3148. "Enumerated area out of bounds");
  3149. // We must ensure that for DrvBitBlt, pco->rclBounds intersects
  3150. // with prclDst, otherwise drivers like the VGA will crash in
  3151. // their DC_COMPLEX code because they don't check for
  3152. // intersection:
  3153. if ((pco == NULL) ||
  3154. bIntersect(&rclSubDst, &rclBounds, &pco->rclBounds))
  3155. {
  3156. if (rop4 == 0xcccc)
  3157. {
  3158. OFFCOPYBITS(pOffDst, psoDst, pOffSrc, psoSrc,
  3159. pco, pxlo, &rclSubDst, (POINTL*) &rclSubSrc);
  3160. }
  3161. else
  3162. {
  3163. if (pptlMsk)
  3164. {
  3165. ptlSubMsk.x
  3166. = pptlMsk->x + (rclSubDst.left - prclDst->left);
  3167. ptlSubMsk.y
  3168. = pptlMsk->y + (rclSubDst.top - prclDst->top);
  3169. }
  3170. OFFBITBLT(pOffDst, psoDst, pOffSrc, psoSrc,
  3171. psoMsk, pco, pxlo, &rclSubDst,
  3172. (POINTL*) &rclSubSrc, &ptlSubMsk, pbo,
  3173. pptlBrush, rop4);
  3174. }
  3175. }
  3176. } while (bSubMore);
  3177. } while (Enum.bEnumLayers(&pSpriteDst));
  3178. // We recomposite here as we do every sprite, instead of one big
  3179. // 'vSpRedrawArea(pState, prclDst)' at the end, to reduce the visible
  3180. // tearing:
  3181. if (pSpriteDst != NULL)
  3182. vSpRedrawArea(pState, &rclDst);
  3183. } while (bMore);
  3184. }
  3185. // Restore the clip object's original bounds, which we mucked with:
  3186. if (pco != NULL)
  3187. pco->rclBounds = rclBounds;
  3188. // If parts of the screen are locked by DirectDraw, we may also have to
  3189. // update the area in the locked area, which we didn't do above:
  3190. if (pState->prgnUnlocked != NULL)
  3191. vSpUpdateLockedScreenAreas(pState, &gptlZero, prclDst, pco, FALSE);
  3192. return(TRUE);
  3193. }
  3194. /******************************Public*Routine******************************\
  3195. * BOOL bSpBltFromScreen
  3196. *
  3197. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3198. * Wrote it.
  3199. \**************************************************************************/
  3200. BOOL bSpBltFromScreen(
  3201. SURFOBJ* psoDst, // Might be a sprite underlay surface, used
  3202. // by vSpUpdate for moving a sprite
  3203. SURFOBJ* psoSrc, // Always the primary screen
  3204. SURFOBJ* psoMsk,
  3205. CLIPOBJ* pco,
  3206. XLATEOBJ* pxlo,
  3207. RECTL* prclDst,
  3208. POINTL* pptlSrc,
  3209. POINTL* pptlMsk,
  3210. BRUSHOBJ* pbo,
  3211. POINTL* pptlBrush,
  3212. ROP4 rop4)
  3213. {
  3214. SPRITESTATE* pState;
  3215. LONG dx;
  3216. LONG dy;
  3217. POINTL Offset;
  3218. ULONG iDirection;
  3219. RECTL rclSrc;
  3220. RECTL rclDst;
  3221. POINTL ptlMsk;
  3222. SPRITE* pSpriteSrc;
  3223. RECTL* prclBounds;
  3224. BYTE iDComplexity;
  3225. RECTL rclBounds;
  3226. BOOL bMore;
  3227. POINTL* pOffSrc;
  3228. PDEVOBJ po(psoSrc->hdev);
  3229. pState = po.pSpriteState();
  3230. // To allow software cursors to work, we have to respect the
  3231. // 'bInsideDriverCall' flag to allow the simulations to read
  3232. // directly from the screen. We also have to be sure that
  3233. // CopyBits calls get sent to CopyBits, otherwise the VGA
  3234. // driver (and possibly others) will crash.
  3235. // Also, if the 'IncludeSprites' flag is set in the destination surface,
  3236. // this is a signal GreStretchBltInternal that we should do a direct blt.
  3237. // (i.e. the ROP passed to StretchBlt/BitBlt had the CAPTUREBLT flag
  3238. // set.) [Bug #278291]
  3239. if ((pState->bInsideDriverCall) ||
  3240. (SURFOBJ_TO_SURFACE(psoDst)->bIncludeSprites()))
  3241. {
  3242. // Grab the sprite lock (needed for the CAPTUREBLT case).
  3243. SPRITELOCK slock(po);
  3244. if (rop4 == 0xcccc)
  3245. {
  3246. return(OFFCOPYBITS(&gptlZero, psoDst, &gptlZero, psoSrc, pco,
  3247. pxlo, prclDst, pptlSrc));
  3248. }
  3249. else
  3250. {
  3251. return(OFFBITBLT(&gptlZero, psoDst, &gptlZero, psoSrc, psoMsk,
  3252. pco, pxlo, prclDst, pptlSrc, pptlMsk, pbo,
  3253. pptlBrush, rop4));
  3254. }
  3255. }
  3256. // Restore the surface's original attributes.
  3257. SPRITELOCK slock(po);
  3258. dx = prclDst->left - pptlSrc->x;
  3259. dy = prclDst->top - pptlSrc->y;
  3260. rclSrc.left = pptlSrc->x;
  3261. rclSrc.top = pptlSrc->y;
  3262. rclSrc.right = prclDst->right - dx;
  3263. rclSrc.bottom = prclDst->bottom - dy;
  3264. // If parts of the screen are locked by DirectDraw, update our underlay
  3265. // buffers for the portion read by the blt:
  3266. if (pState->prgnUnlocked != NULL)
  3267. {
  3268. Offset.x = -dx;
  3269. Offset.y = -dy;
  3270. vSpUpdateLockedScreenAreas(pState, &Offset, prclDst, pco, TRUE);
  3271. }
  3272. // We have to enumerate the rectangles according to the blt direction
  3273. // because vSpUpdate may call us with a sprite underlay surface as
  3274. // 'psoDst' in order to move a sprite.
  3275. if (dx > 0)
  3276. iDirection = (dy > 0) ? CD_LEFTUP : CD_LEFTDOWN;
  3277. else
  3278. iDirection = (dy > 0) ? CD_RIGHTUP : CD_RIGHTDOWN;
  3279. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  3280. if (iDComplexity != DC_TRIVIAL)
  3281. rclBounds = pco->rclBounds;
  3282. ENUMAREAS Enum(pState, &rclSrc, iDirection);
  3283. do {
  3284. bMore = Enum.bEnum(&pSpriteSrc, &rclSrc);
  3285. rclDst.left = rclSrc.left + dx;
  3286. rclDst.right = rclSrc.right + dx;
  3287. rclDst.top = rclSrc.top + dy;
  3288. rclDst.bottom = rclSrc.bottom + dy;
  3289. // We must ensure that for DrvBitBlt, pco->rclBounds intersects
  3290. // with prclDst, otherwise drivers like the VGA will crash in
  3291. // their DC_COMPLEX code because they don't check for
  3292. // intersection:
  3293. if ((iDComplexity == DC_TRIVIAL) ||
  3294. bIntersect(&rclDst, &rclBounds, &pco->rclBounds))
  3295. {
  3296. if (pSpriteSrc == NULL)
  3297. {
  3298. psoSrc = pState->psoScreen;
  3299. pOffSrc = &gptlZero;
  3300. }
  3301. else
  3302. {
  3303. psoSrc = pSpriteSrc->psoUnderlay;
  3304. pOffSrc = &pSpriteSrc->OffUnderlay;
  3305. }
  3306. if (rop4 == 0xcccc)
  3307. {
  3308. OFFCOPYBITS(&gptlZero, psoDst, pOffSrc, psoSrc, pco,
  3309. pxlo, &rclDst, (POINTL*) &rclSrc);
  3310. }
  3311. else
  3312. {
  3313. if (pptlMsk)
  3314. {
  3315. ptlMsk.x = pptlMsk->x + (rclDst.left - prclDst->left);
  3316. ptlMsk.y = pptlMsk->y + (rclDst.top - prclDst->top);
  3317. }
  3318. OFFBITBLT(&gptlZero, psoDst, pOffSrc, psoSrc, psoMsk,
  3319. pco, pxlo, &rclDst, (POINTL*) &rclSrc, &ptlMsk, pbo,
  3320. pptlBrush, rop4);
  3321. }
  3322. }
  3323. } while (bMore);
  3324. // Restore the clip object's original bounds, which we mucked with:
  3325. if (iDComplexity != DC_TRIVIAL)
  3326. pco->rclBounds = rclBounds;
  3327. return(TRUE);
  3328. }
  3329. /******************************Public*Routine******************************\
  3330. * BOOL SpBitBlt
  3331. *
  3332. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3333. * Wrote it.
  3334. \**************************************************************************/
  3335. BOOL SpBitBlt(
  3336. SURFOBJ* psoDst,
  3337. SURFOBJ* psoSrc,
  3338. SURFOBJ* psoMsk,
  3339. CLIPOBJ* pco,
  3340. XLATEOBJ* pxlo,
  3341. RECTL* prclDst,
  3342. POINTL* pptlSrc,
  3343. POINTL* pptlMsk,
  3344. BRUSHOBJ* pbo,
  3345. POINTL* pptlBrush,
  3346. ROP4 rop4)
  3347. {
  3348. SPRITESTATE* pState;
  3349. PFN_DrvBitBlt pfnBitBlt;
  3350. RECTL rclDstOriginal;
  3351. POINTL OffDst;
  3352. RECTL rclDst;
  3353. POINTL ptlSrc;
  3354. POINTL ptlMsk;
  3355. LONG dx;
  3356. LONG dy;
  3357. BOOL bRet = TRUE;
  3358. PDEVOBJ poSrc((psoSrc != NULL) ? psoSrc->hdev : NULL);
  3359. // Handle the hard cases with specific routines:
  3360. if ((poSrc.bValid()) && (psoSrc == poSrc.pSpriteState()->psoScreen))
  3361. {
  3362. pfnBitBlt = (psoDst == psoSrc) ? bSpBltScreenToScreen : bSpBltFromScreen;
  3363. bRet = pfnBitBlt(psoDst, psoSrc, psoMsk, pco, pxlo, prclDst, pptlSrc,
  3364. pptlMsk, pbo, pptlBrush, rop4);
  3365. }
  3366. else
  3367. {
  3368. // Watch out for calls that point 'prclDst' to 'pco->rclBounds', which
  3369. // we'll be modifying:
  3370. rclDstOriginal = *prclDst;
  3371. ENUMUNDERLAYS Enum(psoDst, pco, prclDst);
  3372. while (Enum.bEnum(&psoDst, &OffDst, &pco))
  3373. {
  3374. if (rop4 == 0xcccc)
  3375. {
  3376. bRet &= OFFCOPYBITS(&OffDst, psoDst, &gptlZero, psoSrc,
  3377. pco, pxlo, &rclDstOriginal, pptlSrc);
  3378. }
  3379. else if ((rop4 & 0xff) == (rop4 >> 8))
  3380. {
  3381. bRet &= OFFBITBLT(&OffDst, psoDst, &gptlZero, psoSrc,
  3382. psoMsk, pco, pxlo, &rclDstOriginal, pptlSrc,
  3383. pptlMsk, pbo, pptlBrush, rop4);
  3384. }
  3385. else
  3386. {
  3387. // A lot of drivers don't properly handle adjusting 'pptlMsk'
  3388. // in their DrvBitBlt 'punt' code when *prclDst is larger than
  3389. // pco->rclBounds. So what we'll do here is muck with the
  3390. // parameters to ensure that *prclDst is not larger than
  3391. // pco->rclBounds.
  3392. //
  3393. // Note that this problem does not typically appear without
  3394. // sprites, as NtGdiMaskBlt automatically does this before
  3395. // calling DrvBitBlt. It's only our ENUMUNDERLAYS code above
  3396. // which generates this sort of clipping.
  3397. rclDst = rclDstOriginal;
  3398. if ((!pco) || // If pco is NULL, don't call bIntersect
  3399. bIntersect(&pco->rclBounds, &rclDstOriginal, &rclDst))
  3400. {
  3401. dx = rclDst.left - rclDstOriginal.left;
  3402. dy = rclDst.top - rclDstOriginal.top;
  3403. POINTL* ptlSrcAdjusted = NULL;
  3404. if (pptlSrc)
  3405. {
  3406. ptlSrc.x = pptlSrc->x + dx;
  3407. ptlSrc.y = pptlSrc->y + dy;
  3408. ptlSrcAdjusted = &ptlSrc;
  3409. }
  3410. POINTL* ptlMskAdjusted = NULL;
  3411. if (pptlMsk)
  3412. {
  3413. ptlMsk.x = pptlMsk->x + dx;
  3414. ptlMsk.y = pptlMsk->y + dy;
  3415. ptlMskAdjusted = &ptlMsk;
  3416. }
  3417. bRet &= OFFBITBLT(&OffDst, psoDst, &gptlZero, psoSrc,
  3418. psoMsk, pco, pxlo, &rclDst, ptlSrcAdjusted,
  3419. ptlMskAdjusted, pbo, pptlBrush, rop4);
  3420. }
  3421. }
  3422. }
  3423. }
  3424. return(bRet);
  3425. }
  3426. /******************************Public*Routine******************************\
  3427. * BOOL SpCopyBits
  3428. *
  3429. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3430. * Wrote it.
  3431. \**************************************************************************/
  3432. BOOL SpCopyBits(
  3433. SURFOBJ* psoDst,
  3434. SURFOBJ* psoSrc,
  3435. CLIPOBJ* pco,
  3436. XLATEOBJ* pxlo,
  3437. RECTL* prclDst,
  3438. POINTL* pptlSrc)
  3439. {
  3440. return(SpBitBlt(psoDst, psoSrc, NULL, pco, pxlo, prclDst, pptlSrc, NULL,
  3441. NULL, NULL, 0xcccc));
  3442. }
  3443. /******************************Public*Routine******************************\
  3444. * BOOL SpStretchBlt
  3445. *
  3446. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3447. * Wrote it.
  3448. \**************************************************************************/
  3449. BOOL SpStretchBlt( // Is this call really needed?
  3450. SURFOBJ* psoDst,
  3451. SURFOBJ* psoSrc,
  3452. SURFOBJ* psoMsk,
  3453. CLIPOBJ* pco,
  3454. XLATEOBJ* pxlo,
  3455. COLORADJUSTMENT* pca,
  3456. POINTL* pptlHTOrg,
  3457. RECTL* prclDst,
  3458. RECTL* prclSrc,
  3459. POINTL* pptlMsk,
  3460. ULONG iMode)
  3461. {
  3462. BOOL bRet = TRUE;
  3463. ERECTL erclDraw;
  3464. POINTL Offset;
  3465. // The source rectangle should not exceed the bounds
  3466. // of the surface - that should have been handled by GDI.
  3467. // (bug 77102 - see EngStretchBlt)
  3468. ASSERTGDI((prclSrc->left >= 0) &&
  3469. (prclSrc->top >= 0) &&
  3470. (prclSrc->right <= psoSrc->sizlBitmap.cx) &&
  3471. (prclSrc->bottom <= psoSrc->sizlBitmap.cy),
  3472. "Source rectangle exceeds source surface");
  3473. // I can't be bothered to handle the code that Stretchblt's when the
  3474. // source is the screen. To handle those cases, we would have to
  3475. // exclude all the sprites on the read, just as bSpBltFromScreen does.
  3476. // Fortunately, we've marked the screen surface as STYPE_DEVICE and
  3477. // so the Eng function will punt via SpCopyBits, which does do the
  3478. // right thing:
  3479. PDEVOBJ poSrc(psoSrc->hdev);
  3480. if ((poSrc.bValid()) && (poSrc.pSpriteState()->psoScreen == psoSrc))
  3481. {
  3482. return(EngStretchBlt(psoDst, psoSrc, psoMsk, pco, pxlo, pca,
  3483. pptlHTOrg, prclDst, prclSrc, pptlMsk, iMode));
  3484. }
  3485. // The destination rectangle on a stretch will be poorly ordered when
  3486. // inverting or mirroring:
  3487. erclDraw = *prclDst;
  3488. erclDraw.vOrder();
  3489. ENUMUNDERLAYS Enum(psoDst, pco, &erclDraw);
  3490. while (Enum.bEnum(&psoDst, &Offset, &pco))
  3491. {
  3492. bRet &= OffStretchBlt(PPFNDIRECT(psoDst, StretchBlt), &Offset, psoDst,
  3493. &gptlZero, psoSrc, psoMsk, pco, pxlo, pca, pptlHTOrg,
  3494. prclDst, prclSrc, pptlMsk, iMode);
  3495. }
  3496. return(bRet);
  3497. }
  3498. /******************************Public*Routine******************************\
  3499. * BOOL SpStretchBltROP
  3500. *
  3501. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3502. * Wrote it.
  3503. \**************************************************************************/
  3504. BOOL SpStretchBltROP(
  3505. SURFOBJ* psoDst,
  3506. SURFOBJ* psoSrc,
  3507. SURFOBJ* psoMsk,
  3508. CLIPOBJ* pco,
  3509. XLATEOBJ* pxlo,
  3510. COLORADJUSTMENT* pca,
  3511. POINTL* pptlHTOrg,
  3512. RECTL* prclDst,
  3513. RECTL* prclSrc,
  3514. POINTL* pptlMsk,
  3515. ULONG iMode,
  3516. BRUSHOBJ* pbo,
  3517. DWORD rop4)
  3518. {
  3519. BOOL bRet = TRUE;
  3520. ERECTL erclDraw;
  3521. POINTL Offset;
  3522. // The source rectangle should not exceed the bounds
  3523. // of the surface - that should have been handled by GDI.
  3524. // (bug 77102 - see EngStretchBlt)
  3525. ASSERTGDI((prclSrc->left >= 0) &&
  3526. (prclSrc->top >= 0) &&
  3527. (prclSrc->right <= psoSrc->sizlBitmap.cx) &&
  3528. (prclSrc->bottom <= psoSrc->sizlBitmap.cy),
  3529. "Source rectangle exceeds source surface");
  3530. // I can't be bothered to handle the code that Stretchblt's when the
  3531. // source is the screen. To handle those cases, we would have to
  3532. // exclude all the sprites on the read, just as bSpBltFromScreen does.
  3533. // Fortunately, we've marked the screen surface as STYPE_DEVICE and
  3534. // so the Eng function will punt via SpCopyBits, which does do the
  3535. // right thing:
  3536. PDEVOBJ poSrc(psoSrc->hdev);
  3537. if ((poSrc.bValid()) && (poSrc.pSpriteState()->psoScreen == psoSrc))
  3538. {
  3539. return(EngStretchBltROP(psoDst, psoSrc, psoMsk, pco, pxlo, pca,
  3540. pptlHTOrg, prclDst, prclSrc, pptlMsk, iMode,
  3541. pbo, rop4));
  3542. }
  3543. // The destination rectangle on a stretch will be poorly ordered when
  3544. // inverting or mirroring:
  3545. erclDraw = *prclDst;
  3546. erclDraw.vOrder();
  3547. ENUMUNDERLAYS Enum(psoDst, pco, &erclDraw);
  3548. while (Enum.bEnum(&psoDst, &Offset, &pco))
  3549. {
  3550. bRet &= OffStretchBltROP(PPFNDIRECT(psoDst, StretchBltROP), &Offset,
  3551. psoDst, &gptlZero, psoSrc, psoMsk, pco, pxlo, pca,
  3552. pptlHTOrg, prclDst, prclSrc, pptlMsk, iMode,
  3553. pbo, rop4);
  3554. }
  3555. return(bRet);
  3556. }
  3557. /******************************Public*Routine******************************\
  3558. * BOOL SpTextOut
  3559. *
  3560. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3561. * Wrote it.
  3562. \**************************************************************************/
  3563. BOOL SpTextOut(
  3564. SURFOBJ* pso,
  3565. STROBJ* pstro,
  3566. FONTOBJ* pfo,
  3567. CLIPOBJ* pco,
  3568. RECTL* prclExtra,
  3569. RECTL* prclOpaque,
  3570. BRUSHOBJ* pboFore,
  3571. BRUSHOBJ* pboOpaque,
  3572. POINTL* pptlOrg,
  3573. MIX mix)
  3574. {
  3575. BOOL bRet = TRUE;
  3576. RECTL* prclBounds;
  3577. POINTL Offset;
  3578. ULONG cgposCopied;
  3579. BOOL bEngTextOutOnly;
  3580. PFN_DrvTextOut pfnTextOut;
  3581. // Some drivers can't handle antialiased text, so in those cases don't
  3582. // try to call the driver. Note that we are calling 'SpTextOut' in the
  3583. // first place for these cases to allow 'EngTextOut' to draw directly on
  3584. // the bits if the surface is an STYPE_BITMAP surface, even if a sprite
  3585. // is on the screen.
  3586. bEngTextOutOnly = FALSE;
  3587. if (pfo->flFontType & FO_GRAY16)
  3588. {
  3589. PDEVOBJ po(pso->hdev);
  3590. if (!(po.flGraphicsCapsNotDynamic() & GCAPS_GRAY16) || (pfo->flFontType & FO_CLEARTYPE_X))
  3591. {
  3592. bEngTextOutOnly = TRUE;
  3593. }
  3594. }
  3595. cgposCopied = ((ESTROBJ*)pstro)->cgposCopied;
  3596. prclBounds = (prclOpaque != NULL) ? prclOpaque : &pstro->rclBkGround;
  3597. ENUMUNDERLAYS Enum(pso, pco, prclBounds);
  3598. while (Enum.bEnum(&pso, &Offset, &pco))
  3599. {
  3600. ((ESTROBJ*)pstro)->cgposCopied = cgposCopied;
  3601. pfnTextOut = (bEngTextOutOnly) ? EngTextOut : PPFNDIRECT(pso, TextOut);
  3602. bRet &= OffTextOut(pfnTextOut, &Offset, pso, pstro, pfo,
  3603. pco, prclExtra, prclOpaque, pboFore, pboOpaque,
  3604. pptlOrg, mix);
  3605. }
  3606. return(bRet);
  3607. }
  3608. /******************************Public*Routine******************************\
  3609. * BOOL SpLineTo
  3610. *
  3611. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3612. * Wrote it.
  3613. \**************************************************************************/
  3614. BOOL SpLineTo(
  3615. SURFOBJ *pso,
  3616. CLIPOBJ *pco,
  3617. BRUSHOBJ *pbo,
  3618. LONG x1,
  3619. LONG y1,
  3620. LONG x2,
  3621. LONG y2,
  3622. RECTL *prclBounds,
  3623. MIX mix)
  3624. {
  3625. BOOL bRet = TRUE;
  3626. POINTL Offset;
  3627. ENUMUNDERLAYS Enum(pso, pco, prclBounds);
  3628. while (Enum.bEnum(&pso, &Offset, &pco))
  3629. {
  3630. bRet &= OffLineTo(PPFNDIRECT(pso, LineTo), &Offset, pso, pco, pbo,
  3631. x1, y1, x2, y2, prclBounds, mix);
  3632. }
  3633. return(bRet);
  3634. }
  3635. /******************************Public*Routine******************************\
  3636. * BOOL SpDrawStream
  3637. *
  3638. * 1-27-2001 bhouse
  3639. * Wrote it.
  3640. \**************************************************************************/
  3641. BOOL SpDrawStream(
  3642. SURFOBJ* psoDst,
  3643. SURFOBJ* psoSrc,
  3644. CLIPOBJ* pco,
  3645. XLATEOBJ* pxlo,
  3646. PRECTL prclDstBounds,
  3647. PPOINTL pptlDstOffset,
  3648. ULONG ulIn,
  3649. PVOID pvIn,
  3650. DSSTATE* pdss)
  3651. {
  3652. BOOL bRet = TRUE;
  3653. POINTL Offset;
  3654. // DbgPrint("SpDrawStream entered\n");
  3655. // source can't be the screen
  3656. PDEVOBJ poSrc(psoSrc->hdev);
  3657. if ((poSrc.bValid()) && (poSrc.pSpriteState()->psoScreen == psoSrc))
  3658. {
  3659. DbgPrint("SpDrawStream: source is the screen, this should never happen\n");
  3660. return bRet;
  3661. }
  3662. // The source is not the screen. Only need to worry about enumerating
  3663. // the sprites overlaying the destination.
  3664. ENUMUNDERLAYS Enum(psoDst, pco, prclDstBounds);
  3665. while (Enum.bEnum(&psoDst, &Offset, &pco))
  3666. {
  3667. bRet &= OffDrawStream(PPFNDIRECTENG(psoDst, DrawStream), &Offset,
  3668. psoDst, psoSrc, pco, pxlo, prclDstBounds,
  3669. pptlDstOffset,
  3670. ulIn, pvIn, pdss);
  3671. }
  3672. // DbgPrint("SpDrawStream returning\n");
  3673. return(bRet);
  3674. }
  3675. /******************************Public*Routine******************************\
  3676. * BOOL SpTransparentBlt
  3677. *
  3678. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3679. * Wrote it.
  3680. \**************************************************************************/
  3681. BOOL SpTransparentBlt(
  3682. SURFOBJ *psoDst,
  3683. SURFOBJ *psoSrc,
  3684. CLIPOBJ *pco,
  3685. XLATEOBJ *pxlo,
  3686. RECTL *prclDst,
  3687. RECTL *prclSrc,
  3688. ULONG iTransColor,
  3689. ULONG ulReserved)
  3690. {
  3691. BOOL bRet = TRUE;
  3692. POINTL Offset;
  3693. // I can't be bothered to handle the code that TransparentBlt's when the
  3694. // source is the screen. To handle those cases, we would have to
  3695. // exclude all the sprites on the read, just as bSpBltFromScreen does.
  3696. // Fortunately, we've marked the screen surface as STYPE_DEVICE and
  3697. // so the Eng function will punt via SpCopyBits, which does do the
  3698. // right thing:
  3699. PDEVOBJ poSrc(psoSrc->hdev);
  3700. if ((poSrc.bValid()) && (poSrc.pSpriteState()->psoScreen == psoSrc))
  3701. {
  3702. return(EngTransparentBlt(psoDst, psoSrc, pco, pxlo, prclDst,
  3703. prclSrc, iTransColor, ulReserved));
  3704. }
  3705. // The source is not the screen. Only need to worry about enumerating
  3706. // the sprites overlaying the destination.
  3707. ENUMUNDERLAYS Enum(psoDst, pco, prclDst);
  3708. while (Enum.bEnum(&psoDst, &Offset, &pco))
  3709. {
  3710. bRet &= OffTransparentBlt(PPFNDIRECT(psoDst, TransparentBlt), &Offset,
  3711. psoDst, &gptlZero, psoSrc, pco, pxlo, prclDst,
  3712. prclSrc, iTransColor, ulReserved);
  3713. }
  3714. return(bRet);
  3715. }
  3716. /******************************Public*Routine******************************\
  3717. * BOOL SpAlphaBlend
  3718. *
  3719. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3720. * Wrote it.
  3721. \**************************************************************************/
  3722. BOOL SpAlphaBlend(
  3723. SURFOBJ *psoDst,
  3724. SURFOBJ *psoSrc,
  3725. CLIPOBJ *pco,
  3726. XLATEOBJ *pxlo,
  3727. RECTL *prclDst,
  3728. RECTL *prclSrc,
  3729. BLENDOBJ *pBlendObj)
  3730. {
  3731. BOOL bRet = TRUE;
  3732. POINTL Offset;
  3733. // I can't be bothered to handle the code that AlphaBlend's when the
  3734. // source is the screen. To handle those cases, we would have to
  3735. // exclude all the sprites on the read, just as bSpBltFromScreen does.
  3736. // Fortunately, we've marked the screen surface as STYPE_DEVICE and
  3737. // so the Eng function will punt via SpCopyBits, which does do the
  3738. // right thing:
  3739. PDEVOBJ poSrc(psoSrc->hdev);
  3740. if ((poSrc.bValid()) && (poSrc.pSpriteState()->psoScreen == psoSrc))
  3741. {
  3742. return(EngAlphaBlend(psoDst, psoSrc, pco, pxlo, prclDst,
  3743. prclSrc, pBlendObj));
  3744. }
  3745. // The source is not the screen. Only need to worry about enumerating
  3746. // the sprites overlaying the destination.
  3747. ENUMUNDERLAYS Enum(psoDst, pco, prclDst);
  3748. while (Enum.bEnum(&psoDst, &Offset, &pco))
  3749. {
  3750. bRet &= OffAlphaBlend(PPFNDIRECT(psoDst, AlphaBlend), &Offset, psoDst,
  3751. &gptlZero, psoSrc, pco, pxlo,
  3752. prclDst, prclSrc, pBlendObj);
  3753. }
  3754. return(bRet);
  3755. }
  3756. /******************************Public*Routine******************************\
  3757. * BOOL SpPlgBlt
  3758. *
  3759. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3760. * Wrote it.
  3761. \**************************************************************************/
  3762. BOOL SpPlgBlt(
  3763. SURFOBJ* psoDst,
  3764. SURFOBJ* psoSrc,
  3765. SURFOBJ* psoMsk,
  3766. CLIPOBJ* pco,
  3767. XLATEOBJ* pxlo,
  3768. COLORADJUSTMENT* pca,
  3769. POINTL* pptlBrush,
  3770. POINTFIX* pptfx,
  3771. RECTL* prcl,
  3772. POINTL* pptl,
  3773. ULONG iMode)
  3774. {
  3775. RECTL rclDraw;
  3776. BOOL bRet = TRUE;
  3777. LONG iLeft = (pptfx[1].x > pptfx[0].x) == (pptfx[1].x > pptfx[3].x);
  3778. LONG iTop = (pptfx[1].y > pptfx[0].y) == (pptfx[1].y > pptfx[3].y);
  3779. POINTL Offset;
  3780. // I can't be bothered to handle the code that PlgBlt's when the
  3781. // source is the screen. To handle those cases, we would have to
  3782. // exclude all the sprites on the read, just as bSpBltFromScreen does.
  3783. // Fortunately, we've marked the screen surface as STYPE_DEVICE and
  3784. // so the Eng function will punt via SpCopyBits, which does do the
  3785. // right thing:
  3786. PDEVOBJ poSrc(psoSrc->hdev);
  3787. if ((poSrc.bValid()) && (poSrc.pSpriteState()->psoScreen == psoSrc))
  3788. {
  3789. return(EngPlgBlt(psoDst, psoSrc, psoMsk, pco, pxlo, pca,
  3790. pptlBrush, pptfx, prcl, pptl, iMode));
  3791. }
  3792. if (pptfx[iLeft].x > pptfx[iLeft ^ 3].x)
  3793. {
  3794. iLeft ^= 3;
  3795. }
  3796. if (pptfx[iTop].y > pptfx[iTop ^ 3].y)
  3797. {
  3798. iTop ^= 3;
  3799. }
  3800. rclDraw.left = LONG_FLOOR_OF_FIX(pptfx[iLeft].x) - 1;
  3801. rclDraw.top = LONG_FLOOR_OF_FIX(pptfx[iTop].y) - 1;
  3802. rclDraw.right = LONG_CEIL_OF_FIX(pptfx[iLeft ^ 3].x) + 1;
  3803. rclDraw.bottom = LONG_CEIL_OF_FIX(pptfx[iTop ^ 3].y) + 1;
  3804. ASSERTGDI((rclDraw.left < rclDraw.right) && (rclDraw.top < rclDraw.bottom),
  3805. "Messed up bound calculation");
  3806. ENUMUNDERLAYS Enum(psoDst, pco, &rclDraw);
  3807. while (Enum.bEnum(&psoDst, &Offset, &pco))
  3808. {
  3809. bRet &= OffPlgBlt(PPFNDIRECT(psoDst, PlgBlt), &Offset, psoDst,
  3810. &gptlZero, psoSrc, psoMsk, pco, pxlo, pca, pptlBrush,
  3811. pptfx, prcl, pptl, iMode);
  3812. }
  3813. return(bRet);
  3814. }
  3815. /******************************Public*Routine******************************\
  3816. * BOOL SpGradientFill
  3817. *
  3818. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3819. * Wrote it.
  3820. \**************************************************************************/
  3821. BOOL SpGradientFill(
  3822. SURFOBJ* pso,
  3823. CLIPOBJ* pco,
  3824. XLATEOBJ* pxlo,
  3825. TRIVERTEX* pVertex,
  3826. ULONG nVertex,
  3827. PVOID pMesh,
  3828. ULONG nMesh,
  3829. RECTL* prclExtents,
  3830. POINTL* pptlDitherOrg,
  3831. ULONG ulMode)
  3832. {
  3833. BOOL bRet = TRUE;
  3834. POINTL Offset;
  3835. ENUMUNDERLAYS Enum(pso, pco, prclExtents);
  3836. while (Enum.bEnum(&pso, &Offset, &pco))
  3837. {
  3838. bRet &= OffGradientFill(PPFNDIRECT(pso, GradientFill), &Offset, pso,
  3839. pco, pxlo, pVertex, nVertex, pMesh, nMesh,
  3840. prclExtents, pptlDitherOrg, ulMode);
  3841. }
  3842. return(bRet);
  3843. }
  3844. /******************************Public*Routine******************************\
  3845. * BOOL SpSaveScreenBits
  3846. *
  3847. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3848. * Wrote it.
  3849. \**************************************************************************/
  3850. ULONG_PTR SpSaveScreenBits(
  3851. SURFOBJ* pso,
  3852. ULONG iMode,
  3853. ULONG_PTR ident,
  3854. RECTL* prclSave)
  3855. {
  3856. SPRITESTATE* pState;
  3857. SURFACE* pSurface;
  3858. PTRACKOBJ pto;
  3859. PEWNDOBJ pwo;
  3860. BOOL bIntersectsFunkyFormat;
  3861. BOOL bUnTearDown;
  3862. DEVEXCLUDERECT dxo;
  3863. PDEVOBJ po(pso->hdev);
  3864. po.vAssertDevLock();
  3865. pState = po.pSpriteState();
  3866. pSurface = SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen);
  3867. // For the most part, SaveScreenBits is completely redundant and
  3868. // handled perfectly fine by USER creating a compatible bitmap to
  3869. // hold the backing bits. However, there is one useful scenario
  3870. // for SaveScreenBits: when it occurs on top of a funky pixel-format
  3871. // window as used by some OpenGL hardware. In that case, the window
  3872. // format is not the same as the display, so information would be
  3873. // lost if the bits weren't saved in the original format, which is
  3874. // handled by the driver in DrvSaveScreenBits.
  3875. //
  3876. // So... We expect funky pixel format WNDOBJs to have the NOSPRITES
  3877. // attribute set, meaning we're not supposed to draw any sprites on
  3878. // them.
  3879. if ((pState->pfnSaveScreenBits == NULL) || (gpto == NULL))
  3880. return(0);
  3881. if (iMode == SS_SAVE)
  3882. {
  3883. // We must be holding the WNDOBJ semaphore before mucking
  3884. // with any WNDOBJs.
  3885. SEMOBJ so(ghsemWndobj);
  3886. // See if any funky format WNDOBJ intersects with the requested
  3887. // rectangle.
  3888. bIntersectsFunkyFormat = FALSE;
  3889. for (pto = gpto;
  3890. (pto != NULL) && !bIntersectsFunkyFormat;
  3891. pto = pto->ptoNext)
  3892. {
  3893. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  3894. {
  3895. // The WNDOBJ coordinates must be device-relative so
  3896. // use UNDO:
  3897. UNDODESKTOPCOORD udc(pwo, pState);
  3898. if ((pwo->fl & WO_NOSPRITES) &&
  3899. bIntersect(&pwo->rclBounds, prclSave) &&
  3900. pwo->bInside(prclSave) == REGION_RECT_INTERSECT)
  3901. {
  3902. bIntersectsFunkyFormat = TRUE;
  3903. break;
  3904. }
  3905. }
  3906. }
  3907. // If the requested save rectangle doesn't intersect with any
  3908. // funky WNDOBJ, we can tell USER to revert to the sprite-friendly
  3909. // comaptible-bitmap save-bits method by returning 0.
  3910. if (!bIntersectsFunkyFormat)
  3911. return(0);
  3912. }
  3913. // Tear down any sprites that may overlap the area. This handles the
  3914. // case where the requested save rectangle isn't entirely contained
  3915. // within the WNDOBJ.
  3916. if (iMode != SS_FREE)
  3917. dxo.vExclude(pso->hdev, prclSave);
  3918. return(pState->pfnSaveScreenBits(pso, iMode, ident, prclSave));
  3919. }
  3920. /******************************Public*Routine******************************\
  3921. * BOOL vSpHook
  3922. *
  3923. * Hooks into the DDI between GDI and the display driver to add an
  3924. * additional layer. This only needs to be done when a sprite is
  3925. * visible on the screen (and we take advantage of this to unhook
  3926. * whenever possible, for better performance).
  3927. *
  3928. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3929. * Wrote it.
  3930. \**************************************************************************/
  3931. VOID vSpHook(
  3932. SPRITESTATE* pState)
  3933. {
  3934. PDEVOBJ po(pState->hdev);
  3935. PDEV* ppdev = po.ppdev;
  3936. SURFACE* psurf = po.pSurface();
  3937. ASSERTGDI(!pState->bHooked,
  3938. "Should hook only if already unhooked");
  3939. ASSERTGDI(pState->bInsideDriverCall,
  3940. "SPRITELOCK should be held");
  3941. // Note that the surface's 'iType' and 'flSurfFlags' fields won't
  3942. // be modified to reflect the new state until the SPRITELOCK destructor.
  3943. pState->iSpriteType = STYPE_DEVICE;
  3944. // First, remove all HOOK_ flags for any drawing calls. We do this
  3945. // by removing all HOOK_FLAGS except HOOK_MOVEPANNING and HOOK_SYNCHRONIZE,
  3946. // which aren't really drawing calls:
  3947. pState->flSpriteSurfFlags = psurf->flags() & (~HOOK_FLAGS |
  3948. HOOK_MOVEPANNING |
  3949. HOOK_SYNCHRONIZE);
  3950. // Now add in all the flags for those drawing functions hooked by the
  3951. // sprite layer. Note that for performance reasons HOOK_STROKEANDFILLPATH
  3952. // is not one of these (since no drivers hook DrvStrokeAndFillPath,
  3953. // and EngStrokeAndFillPath isn't smart enough to call DrvStrokePath
  3954. // and DrvFillPath separately, and so we would get no accelerated drawing):
  3955. pState->flSpriteSurfFlags |= (HOOK_BITBLT |
  3956. HOOK_STRETCHBLT |
  3957. HOOK_PLGBLT |
  3958. HOOK_TEXTOUT |
  3959. HOOK_STROKEPATH |
  3960. HOOK_FILLPATH |
  3961. HOOK_LINETO |
  3962. HOOK_COPYBITS |
  3963. HOOK_STRETCHBLTROP |
  3964. HOOK_TRANSPARENTBLT |
  3965. HOOK_ALPHABLEND |
  3966. HOOK_GRADIENTFILL);
  3967. ppdev->apfn[INDEX_DrvStrokePath] = (PFN) SpStrokePath;
  3968. ppdev->apfn[INDEX_DrvFillPath] = (PFN) SpFillPath;
  3969. ppdev->apfn[INDEX_DrvBitBlt] = (PFN) SpBitBlt;
  3970. ppdev->apfn[INDEX_DrvCopyBits] = (PFN) SpCopyBits;
  3971. ppdev->apfn[INDEX_DrvStretchBlt] = (PFN) SpStretchBlt;
  3972. ppdev->apfn[INDEX_DrvTextOut] = (PFN) SpTextOut;
  3973. ppdev->apfn[INDEX_DrvLineTo] = (PFN) SpLineTo;
  3974. ppdev->apfn[INDEX_DrvTransparentBlt] = (PFN) SpTransparentBlt;
  3975. ppdev->apfn[INDEX_DrvAlphaBlend] = (PFN) SpAlphaBlend;
  3976. ppdev->apfn[INDEX_DrvPlgBlt] = (PFN) SpPlgBlt;
  3977. ppdev->apfn[INDEX_DrvGradientFill] = (PFN) SpGradientFill;
  3978. ppdev->apfn[INDEX_DrvDrawStream] = (PFN) SpDrawStream;
  3979. ppdev->apfn[INDEX_DrvStretchBltROP] = (PFN) SpStretchBltROP;
  3980. ppdev->apfn[INDEX_DrvSaveScreenBits] = (PFN) SpSaveScreenBits;
  3981. pState->bHooked = TRUE;
  3982. // Calculate the regions of the screen that shouldn't be drawn upon:
  3983. vSpComputeUnlockedRegion(pState);
  3984. }
  3985. /******************************Public*Routine******************************\
  3986. * BOOL vSpUnhook
  3987. *
  3988. * If there are no visible sprites, unhook from the DDI for better
  3989. * performance.
  3990. *
  3991. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  3992. * Wrote it.
  3993. \**************************************************************************/
  3994. VOID vSpUnhook(
  3995. SPRITESTATE* pState)
  3996. {
  3997. PDEVOBJ po(pState->hdev);
  3998. PDEV* ppdev = po.ppdev;
  3999. SURFACE* psurf = po.pSurface();
  4000. ASSERTGDI(pState->bHooked,
  4001. "Should unhook only if already hooked");
  4002. ASSERTGDI(pState->bInsideDriverCall,
  4003. "SPRITELOCK should be held");
  4004. // Note that the surface's 'iType' and 'flSurfFlags' fields won't
  4005. // be modified to reflect the new state until the SPRITELOCK destructor.
  4006. pState->iSpriteType = pState->iOriginalType;
  4007. pState->flSpriteSurfFlags = pState->flOriginalSurfFlags;
  4008. ppdev->apfn[INDEX_DrvStrokePath] = (PFN) pState->pfnStrokePath;
  4009. ppdev->apfn[INDEX_DrvFillPath] = (PFN) pState->pfnFillPath;
  4010. ppdev->apfn[INDEX_DrvBitBlt] = (PFN) pState->pfnBitBlt;
  4011. ppdev->apfn[INDEX_DrvCopyBits] = (PFN) pState->pfnCopyBits;
  4012. ppdev->apfn[INDEX_DrvStretchBlt] = (PFN) pState->pfnStretchBlt;
  4013. ppdev->apfn[INDEX_DrvTextOut] = (PFN) pState->pfnTextOut;
  4014. ppdev->apfn[INDEX_DrvLineTo] = (PFN) pState->pfnLineTo;
  4015. ppdev->apfn[INDEX_DrvTransparentBlt] = (PFN) pState->pfnTransparentBlt;
  4016. ppdev->apfn[INDEX_DrvAlphaBlend] = (PFN) pState->pfnAlphaBlend;
  4017. ppdev->apfn[INDEX_DrvPlgBlt] = (PFN) pState->pfnPlgBlt;
  4018. ppdev->apfn[INDEX_DrvGradientFill] = (PFN) pState->pfnGradientFill;
  4019. ppdev->apfn[INDEX_DrvStretchBltROP] = (PFN) pState->pfnStretchBltROP;
  4020. ppdev->apfn[INDEX_DrvSaveScreenBits] = (PFN) pState->pfnSaveScreenBits;
  4021. ppdev->apfn[INDEX_DrvDrawStream] = (PFN) pState->pfnDrawStream;
  4022. pState->bHooked = FALSE;
  4023. }
  4024. /******************************Public*Routine******************************\
  4025. * BOOL bSpIsSystemMemory
  4026. *
  4027. * Simple little routine that returns TRUE if the surface is definitely
  4028. * in system memory; FALSE if it's likely in video memory. (Video memory
  4029. * is slow when we have to read the surface, because reads over the bus
  4030. * are very painful.)
  4031. *
  4032. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  4033. * Wrote it.
  4034. \**************************************************************************/
  4035. inline BOOL bSpIsSystemMemory(
  4036. SURFOBJ* pso)
  4037. {
  4038. return((pso->iType == STYPE_BITMAP) && !(pso->fjBitmap & BMF_NOTSYSMEM));
  4039. }
  4040. /******************************Public*Routine******************************\
  4041. * VOID vSpCreateShape
  4042. *
  4043. * Allocates (if necessary) a new bitmap for the sprite, and copies it.
  4044. *
  4045. * Note: pSprite->psoShape will be NULL if this function fails!
  4046. *
  4047. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  4048. * Wrote it.
  4049. \**************************************************************************/
  4050. VOID vSpCreateShape(
  4051. SPRITE* pSprite,
  4052. POINTL* pOffSrc, // Offset associated with 'psoSrc'
  4053. SURFOBJ* psoSrc,
  4054. XLATEOBJ* pxlo,
  4055. RECTL* prcl,
  4056. PALETTE* ppalSrc,
  4057. ULONG iFormat = 0,// May be '0' to select current screen format
  4058. ULONG bWantSystemMemory = TRUE,
  4059. RECTL* prclDirty = NULL)
  4060. // Requested type, STYPE_DEVBITMAP or STYPE_BITMAP.
  4061. {
  4062. SURFOBJ* psoShape;
  4063. LONG cxSrc;
  4064. LONG cySrc;
  4065. POINTL ptlSrc;
  4066. PFN_DrvCopyBits pfnCopyBits;
  4067. // First, handle the palette references:
  4068. XEPALOBJ palNew(ppalSrc);
  4069. XEPALOBJ palOld(pSprite->ppalShape);
  4070. palNew.vRefPalette();
  4071. palOld.vUnrefPalette();
  4072. pSprite->ppalShape = ppalSrc;
  4073. // Now, handle the bitmap:
  4074. cxSrc = prcl->right - prcl->left;
  4075. cySrc = prcl->bottom - prcl->top;
  4076. if (iFormat == 0)
  4077. iFormat = pSprite->pState->psoScreen->iBitmapFormat;
  4078. // Note that we don't try to create a bitmap of type STYPE_DEVBITMAP
  4079. // if we already have a perfectly satisfactory STYPE_BITMAP sitting
  4080. // around. We do this for the case where we might be low on video
  4081. // memory, so that we don't keep re-allocating on every shape change.
  4082. psoShape = pSprite->psoShape;
  4083. if ((psoShape == NULL) ||
  4084. (!bSpIsSystemMemory(psoShape) && (bWantSystemMemory)) ||
  4085. (psoShape->iBitmapFormat != iFormat) ||
  4086. (psoShape->sizlBitmap.cx < cxSrc) ||
  4087. (psoShape->sizlBitmap.cy < cySrc))
  4088. {
  4089. // Max thing again? Or maybe hint?
  4090. vSpDeleteSurface(psoShape);
  4091. psoShape = psoSpCreateSurface(pSprite->pState,
  4092. iFormat,
  4093. cxSrc,
  4094. cySrc,
  4095. bWantSystemMemory);
  4096. pSprite->psoShape = psoShape;
  4097. }
  4098. if (psoShape != NULL)
  4099. {
  4100. pSprite->OffShape.x = -prcl->left;
  4101. pSprite->OffShape.y = -prcl->top;
  4102. pSprite->iModeFormat = iFormat;
  4103. pSprite->flModeMasks = palNew.flRed() | palNew.flBlu();
  4104. // If they passed us a dirty rectangle, only copy bits on that rectangle
  4105. ERECTL erclDirty = (ERECTL) *prcl;
  4106. if (prclDirty)
  4107. {
  4108. erclDirty *= (*prclDirty);
  4109. }
  4110. if (!erclDirty.bEmpty())
  4111. {
  4112. // Calculate required source rectangle
  4113. ERECTL erclSrc(erclDirty);
  4114. erclSrc += *pOffSrc;
  4115. MULTISURF mSrc(psoSrc, &erclSrc);
  4116. // Be sure to go through the DDI hooks and not directly to the Offset
  4117. // functions so that we can read the surface from the multi-mon screen
  4118. // and the like:
  4119. if (SURFOBJ_TO_SURFACE_NOT_NULL(psoShape)->flags() & HOOK_CopyBits)
  4120. {
  4121. PDEVOBJ poShape(psoShape->hdev);
  4122. // WINBUG #415010 06-12-2001 jasonha Properly fail shape update
  4123. // If bLoadSource fails, we can not guarentee a cross-device
  4124. // copy will succeed. Return failure by setting psoShape = NULL.
  4125. if (!mSrc.bLoadSource(poShape.hdev()))
  4126. {
  4127. vSpDeleteSurface(pSprite->psoShape);
  4128. pSprite->psoShape = NULL;
  4129. return;
  4130. }
  4131. else
  4132. {
  4133. pfnCopyBits = PPFNDRV(poShape,CopyBits);
  4134. }
  4135. }
  4136. else
  4137. {
  4138. PDEVOBJ poSrc(psoSrc->hdev);
  4139. pfnCopyBits = PPFNGET(poSrc,
  4140. CopyBits,
  4141. SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc)->flags());
  4142. }
  4143. OffCopyBits(pfnCopyBits, &pSprite->OffShape, psoShape, &gptlZero, mSrc.pso,
  4144. NULL, pxlo, (RECTL*) &erclDirty, mSrc.pptl());
  4145. }
  4146. }
  4147. }
  4148. /******************************Public*Routine******************************\
  4149. * VOID vSpDeleteShape
  4150. *
  4151. * Deletes any shape surfaces associated with the sprite. Note that this
  4152. * does NOT delete the sprite itself.
  4153. *
  4154. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  4155. * Wrote it.
  4156. \**************************************************************************/
  4157. VOID vSpDeleteShape(
  4158. SPRITE* pSprite)
  4159. {
  4160. if (pSprite->ppalShape != NULL)
  4161. {
  4162. XEPALOBJ palShape(pSprite->ppalShape);
  4163. palShape.vUnrefPalette();
  4164. pSprite->ppalShape = NULL;
  4165. }
  4166. if (pSprite->psoShape != NULL)
  4167. {
  4168. vSpDeleteSurface(pSprite->psoShape);
  4169. pSprite->psoShape = NULL;
  4170. }
  4171. }
  4172. /******************************Public*Routine******************************\
  4173. * BOOL bSpUpdateAlpha
  4174. *
  4175. * Parses the BLENDFUNCTION parameter passed in, to ensure that it is
  4176. * consistent with the type that the sprite originally was created as.
  4177. *
  4178. * Returns FALSE if the specified BLENDFUNCTION cannot be allowed, because
  4179. * of an improper flag or because it's not consistent with the sprite type.
  4180. *
  4181. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  4182. * Wrote it.
  4183. \**************************************************************************/
  4184. BOOL bSpUpdateAlpha(
  4185. SPRITE* pSprite,
  4186. BLENDFUNCTION* pblend,
  4187. BOOL bUpdateOnlyAlpha)
  4188. {
  4189. BOOL bRet = FALSE;
  4190. // Note that we don't allow the AC_SRC_ALPHA status to be different
  4191. // from the previous AC_SRC_ALPHA status.
  4192. if ((pblend->BlendOp != AC_SRC_OVER) ||
  4193. (pblend->BlendFlags != 0) ||
  4194. ((pblend->AlphaFormat & ~AC_SRC_ALPHA) != 0))
  4195. {
  4196. WARNING("bSpUpdateAlpha: Invalid alpha");
  4197. }
  4198. else if (((pSprite->dwShape & ULW_ALPHA) == 0) &&
  4199. (pSprite->psoShape != NULL))
  4200. {
  4201. WARNING("bSpUpdateAlpha: dwShape must be ULW_ALPHA");
  4202. }
  4203. else
  4204. {
  4205. bRet = TRUE;
  4206. if (bUpdateOnlyAlpha)
  4207. pSprite->BlendFunction.SourceConstantAlpha =
  4208. pblend->SourceConstantAlpha;
  4209. else
  4210. pSprite->BlendFunction = *pblend;
  4211. pSprite->dwShape &= ~ULW_OPAQUE;
  4212. pSprite->dwShape |= ULW_ALPHA;
  4213. // When trying to display a sprite at 8bpp, always render
  4214. // it opaque. It beats displaying a crappy image slowly.
  4215. if ((pSprite->pState->iModeFormat <= BMF_8BPP) ||
  4216. (!(pblend->AlphaFormat & AC_SRC_ALPHA) &&
  4217. (pblend->SourceConstantAlpha == 0xff)))
  4218. {
  4219. pSprite->fl |= SPRITE_FLAG_EFFECTIVELY_OPAQUE;
  4220. }
  4221. else
  4222. {
  4223. pSprite->fl &= ~SPRITE_FLAG_EFFECTIVELY_OPAQUE;
  4224. }
  4225. }
  4226. return(bRet);
  4227. }
  4228. /******************************Public*Routine******************************\
  4229. * VOID vSpUpdatePerPixelAlphaFromColorKey
  4230. *
  4231. * Given a 32bpp surface, turns every pixel matching the transparent
  4232. * color transparent, and turns every pixel not matching the transparent
  4233. * color opaque.
  4234. *
  4235. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  4236. * Wrote it.
  4237. \**************************************************************************/
  4238. VOID vSpUpdatePerPixelAlphaFromColorKey(
  4239. SURFOBJ* pso,
  4240. ULONG rgbTransparent,
  4241. RECTL* prclDirty)
  4242. {
  4243. LONG i;
  4244. LONG j;
  4245. BYTE* pScan;
  4246. ULONG* pul;
  4247. ULONG ulTransparent;
  4248. LONG lDelta;
  4249. LONG cx, cy;
  4250. ASSERTGDI((pso->iBitmapFormat == BMF_32BPP) && (pso->iType == STYPE_BITMAP),
  4251. "Expected readable 32bpp ARGB surface only");
  4252. ulTransparent = ((rgbTransparent & 0xff0000) >> 16)
  4253. | ((rgbTransparent & 0x00ff00))
  4254. | ((rgbTransparent & 0x0000ff) << 16);
  4255. ERECTL erectlDirty(0, 0, pso->sizlBitmap.cx, pso->sizlBitmap.cy);
  4256. if (prclDirty)
  4257. {
  4258. // If the caller gives us a dirty rectangle, intersect it with the
  4259. // surface rectangle.
  4260. erectlDirty *= (*prclDirty);
  4261. }
  4262. lDelta = pso->lDelta;
  4263. cx = erectlDirty.right - erectlDirty.left;
  4264. cy = erectlDirty.bottom - erectlDirty.top;
  4265. for (j = cy, pScan = ((BYTE*) pso->pvScan0) + erectlDirty.top * lDelta +
  4266. + erectlDirty.left * sizeof(ULONG);
  4267. j != 0;
  4268. j--, pScan += lDelta)
  4269. {
  4270. for (i = cx, pul = (ULONG*) pScan;
  4271. i != 0;
  4272. i--, pul++)
  4273. {
  4274. if (*pul == ulTransparent)
  4275. {
  4276. // Write a pre-multiplied value of 0:
  4277. *pul = 0;
  4278. }
  4279. else
  4280. {
  4281. // Where the bitmap is not the transparent color, change
  4282. // the alpha value to opaque:
  4283. ((RGBQUAD*) pul)->rgbReserved = 0xff;
  4284. }
  4285. }
  4286. }
  4287. }
  4288. /******************************Public*Routine******************************\
  4289. * BOOL bSpUpdateShape
  4290. *
  4291. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  4292. * Wrote it.
  4293. \**************************************************************************/
  4294. BOOL bSpUpdateShape(
  4295. SPRITE* pSprite,
  4296. DWORD dwShape,
  4297. HDC hdcDst,
  4298. HDC hdcSrc,
  4299. COLORREF crKey,
  4300. BLENDFUNCTION* pblend,
  4301. POINTL* pptlSrc,
  4302. SIZEL* psizl,
  4303. RECTL* prclDirty)
  4304. {
  4305. BOOL bStatus = FALSE; // Assume failure
  4306. SPRITESTATE* pState;
  4307. SURFACE* psurfSrc;
  4308. RECTL rclSrc;
  4309. PALETTE* ppalDst;
  4310. PALETTE* ppalDstDC;
  4311. ULONG iFormat;
  4312. ULONG crTextClr;
  4313. ULONG crBackClr;
  4314. LONG lIcmMode;
  4315. BOOL bWantVideoMemory;
  4316. BOOL bColorKeyAlpha;
  4317. ULONG iSrcTransparent;
  4318. BLENDFUNCTION blend;
  4319. pState = pSprite->pState;
  4320. PDEVOBJ po(pState->hdev);
  4321. // Note that only kerne-mode callers can specify ULW_DRAGRECT, so we
  4322. // don't have to be as paranoid about checking parameters for this
  4323. // case.
  4324. if (dwShape == ULW_DRAGRECT)
  4325. {
  4326. // Note that there's not really a source surface, so this is a
  4327. // little faked.
  4328. pSprite->dwShape = dwShape;
  4329. pSprite->rclSrc.left = 0;
  4330. pSprite->rclSrc.right = psizl->cx;
  4331. pSprite->rclSrc.top = 0;
  4332. pSprite->rclSrc.bottom = psizl->cy;
  4333. pSprite->iModeFormat = pState->iModeFormat;
  4334. pSprite->flModeMasks = pState->flModeMasks;
  4335. return(TRUE);
  4336. }
  4337. if (dwShape == 0)
  4338. {
  4339. dwShape = pSprite->dwShape;
  4340. pblend = &pSprite->BlendFunction;
  4341. }
  4342. if ((pptlSrc == NULL) ||
  4343. (psizl == NULL) ||
  4344. ((pblend == NULL) && (dwShape & ULW_ALPHA)))
  4345. {
  4346. WARNING("bSpUpdateShape: Invalid NULL parameter");
  4347. return(bStatus);
  4348. }
  4349. // The supplied source DC has to either belong to the same PDEV as the
  4350. // sprite, or it has to belong to the multi-monitor meta-PDEV. This is
  4351. // because we do not support the S3 driver reading a device bitmap owned
  4352. // by the MGA driver, for example.
  4353. DCOBJ dcoSrc(hdcSrc);
  4354. if (!dcoSrc.bValid() ||
  4355. dcoSrc.bFullScreen() ||
  4356. ((dcoSrc.hdev() != pState->hdev) && (dcoSrc.hdev() != po.hdevParent())))
  4357. {
  4358. WARNING("bSpUpdateShape: Invalid source DC");
  4359. return(bStatus);
  4360. }
  4361. if (hdcDst == 0)
  4362. {
  4363. // Supply some default information for the palette:
  4364. ppalDstDC = ppalDefault;
  4365. crTextClr = 0x00ffffff;
  4366. crBackClr = 0;
  4367. lIcmMode = 0;
  4368. }
  4369. else
  4370. {
  4371. // Note that with multi-mon, the destination DC may be for a separate
  4372. // PDEV than our own PDEV. That is, the destination DC may be
  4373. // associated with the meta-PDEV while we're drawing to a specific
  4374. // PDEV. This is okay. All we'll be pulling out of the source DC
  4375. // is some palette information.
  4376. DCOBJ dcoDst(hdcDst);
  4377. if (!dcoDst.bValid() ||
  4378. (dcoDst.hdev() != dcoSrc.hdev()) ||
  4379. ((dcoDst.hdev() != pState->hdev) && (dcoDst.hdev() != po.hdevParent())))
  4380. {
  4381. WARNING("bSpUpdateShape: Invalid destination DC");
  4382. return(bStatus);
  4383. }
  4384. ppalDstDC = dcoDst.ppal();
  4385. crTextClr = dcoDst.pdc->crTextClr();
  4386. crBackClr = dcoDst.pdc->crBackClr();
  4387. lIcmMode = dcoDst.pdc->lIcmMode();
  4388. }
  4389. rclSrc.left = pptlSrc->x;
  4390. rclSrc.right = pptlSrc->x + psizl->cx;
  4391. rclSrc.top = pptlSrc->y;
  4392. rclSrc.bottom = pptlSrc->y + psizl->cy;
  4393. psurfSrc = dcoSrc.pSurface();
  4394. if ((psurfSrc != NULL) &&
  4395. (rclSrc.left >= 0) &&
  4396. (rclSrc.top >= 0) &&
  4397. (rclSrc.left < rclSrc.right) &&
  4398. (rclSrc.top < rclSrc.bottom) &&
  4399. (rclSrc.right <= psurfSrc->sizl().cx) &&
  4400. (rclSrc.bottom <= psurfSrc->sizl().cy))
  4401. {
  4402. // Clip prclDirty to the source surface
  4403. if (prclDirty)
  4404. {
  4405. (*((ERECTL *) prclDirty)) *=
  4406. ERECTL(0, 0, psurfSrc->sizl().cx, psurfSrc->sizl().cy);
  4407. }
  4408. EXLATEOBJ xlo;
  4409. XEPALOBJ palSrcDC(dcoSrc.ppal());
  4410. XEPALOBJ palSrc(psurfSrc->ppal());
  4411. XEPALOBJ palRGB(gppalRGB);
  4412. // If both ULW_ALPHA and ULW_COLORKEY are specified, then any
  4413. // pixels that match the color-key are completely transparent,
  4414. // and all other pixels have an alpha value of the global alpha
  4415. // specified.
  4416. //
  4417. // Since we don't have any low-level color-keyed-alpha-code, we
  4418. // simply convert this case to using per-pixel alpha.
  4419. bColorKeyAlpha = ((dwShape == (ULW_ALPHA | ULW_COLORKEY)) &&
  4420. (pblend->AlphaFormat == 0));
  4421. if (bColorKeyAlpha)
  4422. {
  4423. blend = *pblend;
  4424. blend.AlphaFormat = AC_SRC_ALPHA;
  4425. pblend = &blend;
  4426. dwShape = ULW_ALPHA;
  4427. bColorKeyAlpha = TRUE;
  4428. iSrcTransparent = rgbFromColorref(palRGB,
  4429. palSrcDC,
  4430. crKey);
  4431. }
  4432. // See whether we should make the sprite 32bpp, or convert it to
  4433. // being the same format as the screen:
  4434. if ((dwShape == ULW_ALPHA) && (pblend->AlphaFormat & AC_SRC_ALPHA))
  4435. {
  4436. iFormat = BMF_32BPP;
  4437. ppalDst = gppalRGB;
  4438. ppalDstDC = ppalDefault;
  4439. }
  4440. else
  4441. {
  4442. iFormat = 0;
  4443. ppalDst = po.ppalSurf(); // Don't use dcoDst.ppal() because
  4444. // with multimon, this may be the
  4445. } // wrong PDEV
  4446. XEPALOBJ palDstDC(ppalDstDC);
  4447. XEPALOBJ palDst(ppalDst);
  4448. if (xlo.bInitXlateObj(NULL,
  4449. lIcmMode,
  4450. palSrc,
  4451. palDst,
  4452. palSrcDC,
  4453. palDstDC,
  4454. crTextClr,
  4455. crBackClr,
  4456. 0))
  4457. {
  4458. bStatus = TRUE;
  4459. pSprite->dwShape = dwShape;
  4460. pSprite->rclSrc = rclSrc;
  4461. if (dwShape == ULW_OPAQUE)
  4462. {
  4463. pSprite->fl |= SPRITE_FLAG_EFFECTIVELY_OPAQUE;
  4464. bWantVideoMemory = TRUE;
  4465. }
  4466. else if (dwShape == ULW_COLORKEY)
  4467. {
  4468. // Transparency is of course specified using the
  4469. // source DC palette.
  4470. iSrcTransparent = ulGetNearestIndexFromColorref(
  4471. palSrc,
  4472. palSrcDC,
  4473. crKey);
  4474. // ...but we're about to copy the source bitmap to a
  4475. // format that is the same as the screen. So we have
  4476. // to pipe the transparency color through the same
  4477. // conversion that the pixels on the blt go through.
  4478. //
  4479. // Note that this is NOT equivalent to doing:
  4480. //
  4481. // iTransparent = ulGetNearestIndexFromColorref(
  4482. // palDst,
  4483. // palDstDC,
  4484. // crKey)
  4485. //
  4486. // Converting to a compatible bitmap may cause us to
  4487. // increase the transparency color gamut (think of a
  4488. // 24bpp color wash being blt'd with a transparency
  4489. // key to 4bpp). But we do this for two reasons:
  4490. //
  4491. // 1. The shape bitmap is always stored in the same
  4492. // format as the screen, and so may be kept by the
  4493. // driver in off-screen memory and thus be accelerated;
  4494. // 2. On dynamic mode changes, we don't have to keep
  4495. // the source DC palette and source surface palette
  4496. // around to re-compute the proper translate.
  4497. pSprite->iTransparent = XLATEOBJ_iXlate(xlo.pxlo(),
  4498. iSrcTransparent);
  4499. pSprite->fl &= ~SPRITE_FLAG_EFFECTIVELY_OPAQUE;
  4500. bWantVideoMemory
  4501. = (po.flAccelerated() & ACCELERATED_TRANSPARENT_BLT);
  4502. }
  4503. else if (dwShape == ULW_ALPHA)
  4504. {
  4505. if (!bSpUpdateAlpha(pSprite, pblend, FALSE))
  4506. {
  4507. bStatus = FALSE;
  4508. }
  4509. else if ((pblend->AlphaFormat & AC_SRC_ALPHA) &&
  4510. !bIsSourceBGRA(psurfSrc) &&
  4511. !bColorKeyAlpha)
  4512. {
  4513. bStatus = FALSE;
  4514. }
  4515. else if (bColorKeyAlpha)
  4516. {
  4517. // We need to be able to directly muck on the bits,
  4518. // so we don't want video memory:
  4519. bWantVideoMemory = FALSE;
  4520. }
  4521. else if (pblend->AlphaFormat & AC_SRC_ALPHA)
  4522. {
  4523. bWantVideoMemory
  4524. = (po.flAccelerated() & ACCELERATED_PIXEL_ALPHA);
  4525. }
  4526. else
  4527. {
  4528. // There's no per-pixel alpha, so we should convert the
  4529. // bitmap to the video card's preferred format (namely,
  4530. // whatever the format of the primary is).
  4531. bWantVideoMemory
  4532. = (po.flAccelerated() & ACCELERATED_CONSTANT_ALPHA);
  4533. }
  4534. }
  4535. else
  4536. {
  4537. WARNING("bSpUpdateShape: Bad shape");
  4538. bStatus = FALSE;
  4539. }
  4540. if (bStatus)
  4541. {
  4542. // For multi-mon, if the source is the meta-screen, we
  4543. // can't blt to a device surface because the two surfaces
  4544. // would belong to different PDEVs. Since I'm lazy, I'll
  4545. // simply enforce that one of the surfaces is not a device
  4546. // surface, when multi-mon:
  4547. #if 0 // WINBUG 315863/320834: We are leaving this old code till fixes for these bugs bake. We will remove these once the new code has baked,
  4548. if ((psurfSrc->iType() == STYPE_DEVICE) &&
  4549. (po.hdevParent() != po.hdev())) // Child PDEV
  4550. {
  4551. bWantVideoMemory = FALSE;
  4552. }
  4553. else if ((psurfSrc->iType() == STYPE_DEVBITMAP) &&
  4554. (po.hdevParent() != po.hdev()) &&
  4555. (po.flGraphicsCaps() & GCAPS_LAYERED))
  4556. {
  4557. // We are given a meta dfb as source and want to update
  4558. // the shape for a mirrored device sprite. Use the meta
  4559. // dfb's corresponding mirror dev bitmap as source.
  4560. PSURFACE psurfSrcTmp;
  4561. psurfSrcTmp = MulGetDevBitmapFromMasterDFB(psurfSrc,po.hdev());
  4562. if (psurfSrcTmp)
  4563. psurfSrc = psurfSrcTmp;
  4564. else
  4565. {
  4566. // We dont have a mirror dev bitmap. Use the master meta
  4567. // dfb after uncloaking it:
  4568. mSrc.vUnCloak(psurfSrc->pSurfobj());
  4569. }
  4570. }
  4571. #endif
  4572. // If the requested operation isn't accelerated, we convert
  4573. // the source bitmap to a true DIB. We do this on the
  4574. // assumption that the application is animating, and will
  4575. // soon call us again with the same bitmap:
  4576. if ((!bWantVideoMemory) && !bSpIsSystemMemory(psurfSrc->pSurfobj()))
  4577. {
  4578. // We don't care if the operation fails, as it was only a
  4579. // performance hint:
  4580. bConvertDfbDcToDib(&dcoSrc);
  4581. psurfSrc = dcoSrc.pSurface();
  4582. }
  4583. if (bStatus)
  4584. {
  4585. // We temporarily reset the 'bInsideDriverCall' flag for the
  4586. // duration of 'vSpCreateShape' so that the read from the source
  4587. // will be correctly handled if the source is actually the
  4588. // screen. We do this so that we don't capture the contents of
  4589. // other sprites when this happens.
  4590. ASSERTGDI(pState->bInsideDriverCall, "Expected sprite lock held");
  4591. vSpDirectDriverAccess(pState, FALSE);
  4592. vSpCreateShape(pSprite,
  4593. &gptlZero,
  4594. psurfSrc->pSurfobj(),
  4595. xlo.pxlo(),
  4596. &rclSrc,
  4597. ppalDst,
  4598. iFormat,
  4599. !bWantVideoMemory,
  4600. prclDirty);
  4601. // Restore the direct driver access state:
  4602. vSpDirectDriverAccess(pState, TRUE);
  4603. }
  4604. }
  4605. if ((bStatus) && (pSprite->psoShape != NULL))
  4606. {
  4607. // Oh happy times, we succeeded.
  4608. if (bColorKeyAlpha)
  4609. {
  4610. // Anywhere the color-key is, convert it to transparent.
  4611. // Anywhere the color-key isn't, make it opaque:
  4612. vSpUpdatePerPixelAlphaFromColorKey(pSprite->psoShape,
  4613. iSrcTransparent,
  4614. prclDirty);
  4615. }
  4616. }
  4617. else
  4618. {
  4619. // Uh oh, something failed. We have to delete the sprite
  4620. // now because we may have partially wacked some of our
  4621. // pSprite state.
  4622. vSpDeleteShape(pSprite);
  4623. pSprite->dwShape = ULW_OPAQUE; // reset dwShape to
  4624. // something innocuous
  4625. bStatus = FALSE;
  4626. }
  4627. }
  4628. }
  4629. else
  4630. {
  4631. WARNING("bSpUpdateShape: Bad DCs or rectangles");
  4632. }
  4633. return(bStatus);
  4634. }
  4635. /******************************Public*Routine******************************\
  4636. * VOID vSpTransferShape
  4637. *
  4638. * Creates a shape for a new sprite that is a copy of the old.
  4639. *
  4640. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  4641. * Wrote it.
  4642. \**************************************************************************/
  4643. VOID vSpTransferShape(
  4644. SPRITE* pSpriteNew,
  4645. SPRITE* pSpriteOld)
  4646. {
  4647. ASSERTGDI(pSpriteNew->psoShape == NULL,
  4648. "Expected new sprite to have no resources");
  4649. // Transfer HIDDEN state to the new sprite
  4650. pSpriteNew->fl |= pSpriteOld->fl & SPRITE_FLAG_HIDDEN;
  4651. if (pSpriteOld->psoShape != NULL)
  4652. {
  4653. // This will allocate a new sprite bitmap and copy it. Why not
  4654. // simply transfer 'psoShape' from the old sprite to the new?
  4655. // Because it may be a device bitmap!
  4656. vSpCreateShape(pSpriteNew,
  4657. &pSpriteOld->OffShape,
  4658. pSpriteOld->psoShape,
  4659. NULL,
  4660. &pSpriteOld->rclSrc,
  4661. pSpriteOld->ppalShape,
  4662. pSpriteOld->psoShape->iBitmapFormat,
  4663. TRUE); // TRUE because by storing the sprite in
  4664. // system memory, we avoid the 'Both surfaces
  4665. // are unreadable and owned by different
  4666. // PDEVs" assert in vSpCreateShape
  4667. pSpriteNew->dwShape = pSpriteOld->dwShape;
  4668. pSpriteNew->rclSrc = pSpriteOld->rclSrc;
  4669. pSpriteNew->iTransparent = pSpriteOld->iTransparent;
  4670. pSpriteNew->BlendFunction = pSpriteOld->BlendFunction;
  4671. }
  4672. // Transfer the cached attributes to the new sprite
  4673. pSpriteNew->cachedAttributes = pSpriteOld->cachedAttributes;
  4674. }
  4675. /******************************Public*Routine******************************\
  4676. * BOOL SpUpdatePosition
  4677. *
  4678. * NOTE: pSprite->psoShape may very well be NULL when entering this
  4679. * function!
  4680. *
  4681. * NOTE: This function must never fail when hiding the sprite (because
  4682. * that's used for cleanup and error handling)
  4683. *
  4684. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  4685. * Wrote it.
  4686. \**************************************************************************/
  4687. BOOL bSpUpdatePosition(
  4688. SPRITE* pSprite,
  4689. POINTL* pptlDst, // May be NULL
  4690. BOOL bLeaveBits = FALSE)
  4691. {
  4692. GDIFunctionID(bSpUpdatePosition);
  4693. BOOL bStatus = TRUE; // Assume success
  4694. SPRITESTATE* pState;
  4695. ERECTL rclSprite;
  4696. RECTL* prcl;
  4697. ULONG crcl;
  4698. LONG cxSprite;
  4699. LONG cySprite;
  4700. SURFOBJ* psoUnderlay;
  4701. SURFOBJ* psoShape;
  4702. LONG dx;
  4703. LONG dy;
  4704. RECTL rclExclude;
  4705. POINTL OffUnderlay;
  4706. BOOL bWantSystemMemory;
  4707. RECTL rclOldSprite;
  4708. POINTL lastDst;
  4709. FLONG flNewVisibility;
  4710. pState = pSprite->pState;
  4711. lastDst = pSprite->ptlDst;
  4712. if (pptlDst == NULL)
  4713. {
  4714. rclSprite.bottom = LONG_MIN;
  4715. }
  4716. else
  4717. {
  4718. // Remember the original position for later.
  4719. pSprite->ptlDst.x = pptlDst->x;
  4720. pSprite->ptlDst.y = pptlDst->y;
  4721. // Note that our handy 'bIntersect' routine will handle the
  4722. // cases where 'pptlDst' is too big, causing these adds to
  4723. // overflow.
  4724. rclSprite.left = pptlDst->x;
  4725. rclSprite.top = pptlDst->y;
  4726. rclSprite.right = pptlDst->x
  4727. + (pSprite->rclSrc.right - pSprite->rclSrc.left);
  4728. rclSprite.bottom = pptlDst->y
  4729. + (pSprite->rclSrc.bottom - pSprite->rclSrc.top);
  4730. }
  4731. // Non-visible sprites have a sprite rectangle of (LONG_MIN, LONG_MIN,
  4732. // LONG_MIN, LONG_MIN), which is depended upon by
  4733. // vSpComputeSpriteRanges:
  4734. if ((pSprite->fl & (SPRITE_FLAG_CLIPPING_OBSCURED | SPRITE_FLAG_HIDDEN)) ||
  4735. !bIntersect(&pState->rclScreen, &rclSprite, &rclSprite)
  4736. )
  4737. {
  4738. rclSprite.left = LONG_MIN;
  4739. rclSprite.top = LONG_MIN;
  4740. rclSprite.right = LONG_MIN;
  4741. rclSprite.bottom = LONG_MIN;
  4742. flNewVisibility = 0;
  4743. }
  4744. else
  4745. {
  4746. flNewVisibility = SPRITE_FLAG_VISIBLE;
  4747. }
  4748. // WINBUG #368282 05-12-2001 jasonha Correctly maintain cVisible count
  4749. // If an invisible sprite was to be made visible, but the creation
  4750. // of the underlay failed, then it would be included in the cVisible
  4751. // count during the first bSpUpdatePosition call, but not removed
  4752. // during the recursive call to hide the sprite since
  4753. // pSprite->rclSprite would still be empty at all LONG_MIN's.
  4754. // SPRITE_FLAG_VISIBLE is used to represent inclusion in cVisible.
  4755. // If the uncovered region has changed, handle the underlay buffer:
  4756. if ((flNewVisibility != (pSprite->fl & SPRITE_FLAG_VISIBLE)) ||
  4757. (rclSprite.left != pSprite->rclSprite.left ) ||
  4758. (rclSprite.top != pSprite->rclSprite.top ) ||
  4759. (rclSprite.right != pSprite->rclSprite.right ) ||
  4760. (rclSprite.bottom != pSprite->rclSprite.bottom))
  4761. {
  4762. // If the old sprite was visible, decrement the visible sprite
  4763. // count:
  4764. if (pSprite->fl & SPRITE_FLAG_VISIBLE)
  4765. {
  4766. ASSERTGDI(pState->cVisible != 0, "Messed up cVisible count");
  4767. pState->cVisible--;
  4768. pSprite->fl &= ~SPRITE_FLAG_VISIBLE;
  4769. #if DEBUG_SPRITES
  4770. {
  4771. ASSERTGDI(pState->pListVisible != NULL, "Invalid visible sprite list: pState->pListVisible == NULL when removing sprite.\n");
  4772. if (pState->cVisible == 0)
  4773. {
  4774. ASSERTGDI(pState->pListVisible == pSprite, "Invalid visible sprite list: pState->pListVisible != pSprite when removing last sprite.\n");
  4775. ASSERTGDI(pSprite->pNextVisible == NULL, "Invalid visible sprite list: pSprite->pNextVisible != NULL when removing last sprite.\n");
  4776. pState->pListVisible = pSprite->pNextVisible;
  4777. }
  4778. else
  4779. {
  4780. if (pState->pListVisible == pSprite)
  4781. {
  4782. pState->pListVisible = pSprite->pNextVisible;
  4783. }
  4784. else
  4785. {
  4786. SPRITE *pPrevSprite = pState->pListVisible;
  4787. while (pPrevSprite->pNextVisible != pSprite)
  4788. {
  4789. ASSERTGDI(pPrevSprite->pNextVisible != NULL, "Invalid visible sprite list: didn't find sprite in list.\n");
  4790. pPrevSprite = pPrevSprite->pNextVisible;
  4791. }
  4792. pPrevSprite->pNextVisible = pSprite->pNextVisible;
  4793. }
  4794. ASSERTGDI(pState->pListVisible != NULL, "Invalid visible sprite list: pState->pListVisible == NULL after removing non-last sprite.\n");
  4795. pSprite->pNextVisible = NULL;
  4796. }
  4797. }
  4798. #endif
  4799. }
  4800. // If we're shrinking this sprite in any dimension, redraw the newly
  4801. // unobscured portions. Be sure to watch for the failure case where
  4802. // 'psoUnderlay' might not have been allocated:
  4803. if ((pSprite->psoUnderlay) && (!bLeaveBits))
  4804. {
  4805. vSpRedrawUncoveredArea(pSprite, &rclSprite);
  4806. }
  4807. else if (bLeaveBits)
  4808. {
  4809. // Otherwise we should blit the sprite bits onto its position
  4810. // which will have the effect of updating the underlay bits
  4811. // for the overlapping sprites. See bug #252464.
  4812. CLIPOBJ* pco;
  4813. ECLIPOBJ eco;
  4814. if (pSprite->prgnClip)
  4815. {
  4816. eco.vSetup(pSprite->prgnClip, *((ERECTL *) &pSprite->rclSprite));
  4817. pco = &eco;
  4818. }
  4819. else
  4820. {
  4821. pco = NULL;
  4822. }
  4823. // Disable direct driver access for the duration of the
  4824. // SpCopyBits call so that we will be able to enumerate
  4825. // the sprites (see ENUMUNDERLAYS constructor).
  4826. ASSERTGDI(pState->bInsideDriverCall, "Expected sprite lock held");
  4827. vSpDirectDriverAccess(pState, FALSE);
  4828. if((!pco || (!eco.erclExclude().bEmpty())) &&
  4829. (pSprite->psoShape))
  4830. {
  4831. // Let's not worry about setting up a color translation because
  4832. // the format of the sprite and the screen should be the same
  4833. // (only exception is for per pixel alpha sprites, but these
  4834. // shouldn't be using the ULW_NOREPAINT flag). However,
  4835. // it won't hurt to check here anyway and if not true no big deal
  4836. // if we don't update the underlay bits.
  4837. if(pState->psoScreen->iBitmapFormat ==
  4838. pSprite->psoShape->iBitmapFormat)
  4839. {
  4840. POINTL pt;
  4841. // WINFIX #96696 bhouse 4-14-2000
  4842. // Use the correct source point, rclSprite may have been
  4843. // clipped.
  4844. pt.x = pSprite->rclSprite.left - lastDst.x;
  4845. pt.y = pSprite->rclSprite.top - lastDst.y;
  4846. SpCopyBits(pState->psoScreen,
  4847. pSprite->psoShape,
  4848. pco,
  4849. NULL,
  4850. &pSprite->rclSprite,
  4851. &pt);
  4852. }
  4853. else
  4854. {
  4855. WARNING("bSpUpdatePosition: not updating underlay bits");
  4856. }
  4857. }
  4858. // Restore direct driver access
  4859. vSpDirectDriverAccess(pState, TRUE);
  4860. }
  4861. cxSprite = rclSprite.right - rclSprite.left;
  4862. cySprite = rclSprite.bottom - rclSprite.top;
  4863. if (cxSprite == 0)
  4864. {
  4865. // The sprite is not visible, which may have been caused by
  4866. // disabling the sprite. Check to see if there are no other
  4867. // sprites on the screen, which would allow us to unhook the
  4868. // DDI:
  4869. if ((pState->cVisible == 0) && (pState->bHooked))
  4870. vSpUnhook(pState);
  4871. }
  4872. else
  4873. {
  4874. ASSERTGDI(cySprite != 0, "If cxSprite is 0, expected cySprite is 0");
  4875. // Since the new sprite is visible, increment the visible sprite
  4876. // count:
  4877. ASSERTGDI(!(pSprite->fl & SPRITE_FLAG_VISIBLE), "Invalid sprite visible state: making visible again.\n");
  4878. pSprite->fl |= SPRITE_FLAG_VISIBLE;
  4879. pState->cVisible++;
  4880. #if DEBUG_SPRITES
  4881. {
  4882. ASSERTGDI(pSprite->pNextVisible == NULL, "Invalid visible sprite list: pSprite->pNextVisible != NULL when adding to visible list.\n");
  4883. if (pState->cVisible == 1)
  4884. {
  4885. ASSERTGDI(pState->pListVisible == NULL, "Invalid visible sprite list: pState->pListVisible != NULL when adding first sprite.\n");
  4886. }
  4887. else
  4888. {
  4889. ASSERTGDI(pState->pListVisible != NULL, "Invalid visible sprite list: pState->pListVisible == NULL when adding non-first sprite.\n");
  4890. }
  4891. pSprite->pNextVisible = pState->pListVisible;
  4892. pState->pListVisible = pSprite;
  4893. }
  4894. #endif
  4895. // If the DDI isn't already hooked, do it now. This has to
  4896. // occur before we update the shape on the screen, because
  4897. // it recalculates prgnUnlocked, which must be respected
  4898. // whenever we write to the screen.
  4899. if (!pState->bHooked)
  4900. vSpHook(pState);
  4901. // Check to see if the old underlay buffer will do.
  4902. psoUnderlay = pSprite->psoUnderlay;
  4903. if ((psoUnderlay == NULL) ||
  4904. (cxSprite > psoUnderlay->sizlBitmap.cx) ||
  4905. (cySprite > psoUnderlay->sizlBitmap.cy))
  4906. {
  4907. // There is no old underlay surface, or it's not large
  4908. // enough, so allocate a new underlay structure.
  4909. //
  4910. // Note that we don't free the old underlay surface yet,
  4911. // because we need it for the 'bSpBltFromScreen' we're
  4912. // about to do!
  4913. #if DEBUG_SPRITES
  4914. if (psoUnderlay != NULL)
  4915. KdPrint(("Growing psoUnderlay: %p Old: (%li, %li) New: (%li, %li)\n",
  4916. psoUnderlay, psoUnderlay->sizlBitmap.cx, psoUnderlay->sizlBitmap.cy,
  4917. cxSprite, cySprite));
  4918. #endif
  4919. // Because alphablends require read-modify-write operations
  4920. // on the destination, it's a horrible performance penalty
  4921. // if we create the compositing surface in video memory and
  4922. // the device doesn't support accelerated alpha. Similarly,
  4923. // we don't want to have the underlay surface in video memory
  4924. // if the compositing surface is in system memory. So check
  4925. // here if alpha isn't accelerated, and simply create the
  4926. // underlay in system memory.
  4927. bWantSystemMemory = FALSE;
  4928. if (pSprite->dwShape == ULW_ALPHA)
  4929. {
  4930. PDEVOBJ po(pState->hdev);
  4931. if (pSprite->BlendFunction.AlphaFormat & AC_SRC_ALPHA)
  4932. {
  4933. if (!(po.flAccelerated() & ACCELERATED_PIXEL_ALPHA))
  4934. {
  4935. bWantSystemMemory = TRUE;
  4936. }
  4937. }
  4938. else
  4939. {
  4940. if (!(po.flAccelerated() & ACCELERATED_CONSTANT_ALPHA))
  4941. {
  4942. bWantSystemMemory = TRUE;
  4943. }
  4944. }
  4945. }
  4946. {
  4947. PDEVOBJ po(pState->hdev);
  4948. if (po.flGraphicsCaps() & GCAPS_LAYERED)
  4949. bWantSystemMemory = TRUE;
  4950. }
  4951. psoUnderlay = psoSpCreateSurface(
  4952. pState,
  4953. 0,
  4954. max(cxSprite, pSprite->sizlHint.cx),
  4955. max(cySprite, pSprite->sizlHint.cy),
  4956. bWantSystemMemory);
  4957. if (!psoUnderlay)
  4958. {
  4959. // Uh oh, we couldn't allocate the underlay buffer, so
  4960. // we won't be able to show the sprite. We'll handle this
  4961. // by simply marking the sprite as invisible later on:
  4962. bStatus = FALSE;
  4963. }
  4964. else
  4965. {
  4966. psoUnderlay->fjBitmap |= BMF_DONTCACHE;
  4967. // We have turned off BMF_SPRITE support (it appears to
  4968. // be unused)
  4969. // psoUnderlay->fjBitmap |= BMF_SPRITE;
  4970. OffUnderlay.x = -rclSprite.left;
  4971. OffUnderlay.y = -rclSprite.top;
  4972. // Get the bits underneath where the sprite will appear:
  4973. if (((cxSprite <= SMALL_SPRITE_DIMENSION) &&
  4974. (cySprite <= SMALL_SPRITE_DIMENSION)))
  4975. {
  4976. vSpSmallUnderlayCopy(pSprite,
  4977. &OffUnderlay,
  4978. psoUnderlay,
  4979. &pSprite->OffUnderlay,
  4980. pSprite->psoUnderlay,
  4981. 0,
  4982. 0,
  4983. &rclSprite,
  4984. &pSprite->rclSprite);
  4985. }
  4986. else
  4987. {
  4988. vSpBigUnderlayCopy(pState,
  4989. &OffUnderlay,
  4990. psoUnderlay,
  4991. &rclSprite);
  4992. }
  4993. // Okay, we can now safely delete the old underlay:
  4994. vSpDeleteSurface(pSprite->psoUnderlay);
  4995. pSprite->psoUnderlay = psoUnderlay;
  4996. pSprite->OffUnderlay = OffUnderlay;
  4997. pSprite->rclUnderlay.left = rclSprite.left;
  4998. pSprite->rclUnderlay.top = rclSprite.top;
  4999. pSprite->rclUnderlay.right = rclSprite.left
  5000. + psoUnderlay->sizlBitmap.cx;
  5001. pSprite->rclUnderlay.bottom = rclSprite.top
  5002. + psoUnderlay->sizlBitmap.cy;
  5003. }
  5004. }
  5005. else
  5006. {
  5007. // Okay, we know the old underlay surface was already big
  5008. // enough. See if we have to read some bits from the screen
  5009. // to update the underlay, either because the sprite moved
  5010. // or because it got larger:
  5011. if ((rclSprite.left < pSprite->rclSprite.left ) ||
  5012. (rclSprite.top < pSprite->rclSprite.top ) ||
  5013. (rclSprite.right > pSprite->rclSprite.right ) ||
  5014. (rclSprite.bottom > pSprite->rclSprite.bottom))
  5015. {
  5016. dx = 0;
  5017. dy = 0;
  5018. if (rclSprite.left < pSprite->rclUnderlay.left)
  5019. dx = rclSprite.left - pSprite->rclUnderlay.left;
  5020. else if (rclSprite.right > pSprite->rclUnderlay.right)
  5021. dx = rclSprite.right - pSprite->rclUnderlay.right;
  5022. if (rclSprite.top < pSprite->rclUnderlay.top)
  5023. dy = rclSprite.top - pSprite->rclUnderlay.top;
  5024. else if (rclSprite.bottom > pSprite->rclUnderlay.bottom)
  5025. dy = rclSprite.bottom - pSprite->rclUnderlay.bottom;
  5026. // Note that 'dx' and 'dy' may still both be zero.
  5027. pSprite->rclUnderlay.left += dx;
  5028. pSprite->rclUnderlay.right += dx;
  5029. pSprite->rclUnderlay.top += dy;
  5030. pSprite->rclUnderlay.bottom += dy;
  5031. ASSERTGDI(
  5032. (pSprite->rclUnderlay.left <= rclSprite.left) &&
  5033. (pSprite->rclUnderlay.top <= rclSprite.top) &&
  5034. (pSprite->rclUnderlay.right >= rclSprite.right) &&
  5035. (pSprite->rclUnderlay.bottom >= rclSprite.bottom),
  5036. "Improper rclUnderlay");
  5037. // I figure that on a move, the delta will typically be
  5038. // fairly small, so we'll always call 'vSpSmallUnderlayCopy'
  5039. // instead of 'bSpBltFromScreen' for this case.
  5040. pSprite->OffUnderlay.x = -pSprite->rclUnderlay.left;
  5041. pSprite->OffUnderlay.y = -pSprite->rclUnderlay.top;
  5042. vSpSmallUnderlayCopy(pSprite,
  5043. &pSprite->OffUnderlay,
  5044. pSprite->psoUnderlay,
  5045. &pSprite->OffUnderlay,
  5046. pSprite->psoUnderlay,
  5047. dx,
  5048. dy,
  5049. &rclSprite,
  5050. &pSprite->rclSprite);
  5051. }
  5052. }
  5053. }
  5054. if (bStatus)
  5055. {
  5056. rclOldSprite = pSprite->rclSprite;
  5057. // Finally, update the sprite rectangle and mark the range cache
  5058. // as being invalid. Note that we do this only in the case when we
  5059. // can display the sprite.
  5060. pSprite->rclSprite = rclSprite;
  5061. pState->bValidRange = FALSE;
  5062. vSpOrderInY(pSprite);
  5063. // If either a DirectDraw Lock is active, or there are any active
  5064. // WNDOBJs, we have to do some more work to handle repercussions:
  5065. if (gpto != NULL)
  5066. {
  5067. vSpCheckForWndobjOverlap(pState, &rclSprite, &rclOldSprite);
  5068. }
  5069. }
  5070. else
  5071. {
  5072. // If we couldn't display the sprite, then hide it. Note that
  5073. // there's no chance that this will infinitely recurse.
  5074. ASSERTGDI(pptlDst != NULL,
  5075. "bSpUpdatePosition: Must never fail a hide");
  5076. bSpUpdatePosition(pSprite, NULL);
  5077. }
  5078. }
  5079. return(bStatus);
  5080. }
  5081. /******************************Public*Routine******************************\
  5082. * VOID vSpFreeClipResources
  5083. *
  5084. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5085. * Wrote it.
  5086. \**************************************************************************/
  5087. VOID vSpFreeClipResources(
  5088. SPRITE* pSprite)
  5089. {
  5090. RGNOBJ ro(pSprite->prgnClip);
  5091. ro.vDeleteRGNOBJ();
  5092. pSprite->prgnClip = NULL;
  5093. }
  5094. /******************************Public*Routine******************************\
  5095. * BOOL bSpUpdateSprite
  5096. *
  5097. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5098. * Wrote it.
  5099. \**************************************************************************/
  5100. BOOL bSpUpdateSprite(
  5101. SPRITE* pSprite,
  5102. HDC hdcDst,
  5103. POINTL* pptlDst,
  5104. SIZEL* psizl,
  5105. HDC hdcSrc,
  5106. POINTL* pptlSrc,
  5107. COLORREF crKey,
  5108. BLENDFUNCTION* pblend,
  5109. DWORD dwShape,
  5110. RECTL* prclDirty)
  5111. {
  5112. BOOL bStatus;
  5113. SPRITESTATE* pState;
  5114. BLENDFUNCTION blend;
  5115. if (!pSprite)
  5116. {
  5117. return FALSE;
  5118. }
  5119. bStatus = FALSE; // Assume failure
  5120. pState = pSprite->pState;
  5121. PDEVOBJ po(pState->hdev);
  5122. DEVLOCKOBJ dlo(po);
  5123. SPRITELOCK slock(po);
  5124. if (dwShape & ULW_NEW_ATTRIBUTES)
  5125. {
  5126. // Take out this instructions flag to avoid future confusion
  5127. dwShape &= ~ULW_NEW_ATTRIBUTES;
  5128. // Cache new attributes in the sprite
  5129. pSprite->cachedAttributes.dwShape = dwShape;
  5130. pSprite->cachedAttributes.bf = *pblend;
  5131. pSprite->cachedAttributes.crKey = (ULONG) crKey;
  5132. // If sprite hasn't been created yet, don't proceed so that a black
  5133. // sprite won't get painted on the screen. This is the case where
  5134. // we're called for the first time from _UpdateLayeredWindow, where
  5135. // user chooses to not pass us hdcSrc yet.
  5136. if (!hdcSrc)
  5137. {
  5138. return TRUE;
  5139. }
  5140. }
  5141. else if (dwShape == ULW_DEFAULT_ATTRIBUTES)
  5142. {
  5143. // Retrieve arguments from cached values
  5144. dwShape = pSprite->cachedAttributes.dwShape;
  5145. crKey = pSprite->cachedAttributes.crKey;
  5146. blend = pSprite->cachedAttributes.bf; // Better to point to a local
  5147. // variable in case this gets
  5148. // changed later.
  5149. pblend = &blend;
  5150. }
  5151. if ((hdcDst) || (psizl) || (hdcSrc) || (pptlSrc) || (crKey))
  5152. {
  5153. bStatus = bSpUpdateShape(pSprite, dwShape, hdcDst, hdcSrc,
  5154. crKey, pblend, pptlSrc, psizl, prclDirty);
  5155. if (bStatus)
  5156. {
  5157. // Use the last position we were given if no position was specified on
  5158. // this call.
  5159. bStatus &= bSpUpdatePosition(
  5160. pSprite,
  5161. (pptlDst != NULL) ? pptlDst : &pSprite->ptlDst);
  5162. }
  5163. }
  5164. else if (((dwShape == ULW_ALPHA) || (dwShape == (ULW_ALPHA | ULW_COLORKEY))) &&
  5165. (pblend != NULL) &&
  5166. (pptlDst == NULL))
  5167. {
  5168. bStatus = bSpUpdateAlpha(pSprite, pblend, TRUE);
  5169. }
  5170. else if (((dwShape == 0) || (dwShape == ULW_NOREPAINT)) && (pblend == NULL))
  5171. {
  5172. // Note that pptlDst may be either NULL or non-NULL.
  5173. bStatus = bSpUpdatePosition(pSprite, pptlDst, dwShape & ULW_NOREPAINT);
  5174. }
  5175. else
  5176. {
  5177. WARNING("bSpUpdateSprite: Unexpected argument");
  5178. }
  5179. // Finally, redraw the sprite:
  5180. if (prclDirty)
  5181. {
  5182. // Only redraw the dirty rectangle
  5183. ERECTL erclDirty(*prclDirty);
  5184. erclDirty += pSprite->ptlDst; // Offset by origin of sprite window
  5185. // because the rectangle needs to
  5186. // be in screen coordinates
  5187. erclDirty *= pSprite->rclSprite; // To be safe, intersect with sprite
  5188. // rectangle
  5189. if (!erclDirty.bEmpty())
  5190. {
  5191. // Only redraw if intersection is not empty
  5192. vSpRedrawArea(pSprite->pState, (RECTL*) &erclDirty);
  5193. }
  5194. }
  5195. else
  5196. {
  5197. // Must redraw the whole sprite
  5198. vSpRedrawSprite(pSprite);
  5199. // synchrnize on output surface to ensure frame is rendered
  5200. if (!po.bDisabled())
  5201. {
  5202. po.vSync(po.pSurface()->pSurfobj(), NULL, 0);
  5203. }
  5204. }
  5205. return(bStatus);
  5206. }
  5207. /******************************Public*Routine******************************\
  5208. * VOID vSpRenumberZOrder
  5209. *
  5210. * Renumbers the sprites according to z-order, after the z-order is changed.
  5211. *
  5212. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5213. * Wrote it.
  5214. \**************************************************************************/
  5215. VOID vSpRenumberZOrder(
  5216. SPRITESTATE* pState)
  5217. {
  5218. SPRITE* pSprite;
  5219. ULONG z = 0;
  5220. // The sprite numbers are assigned starting at 0 with the back-most sprite:
  5221. for (pSprite = pState->pListZ; pSprite != NULL; pSprite = pSprite->pNextZ)
  5222. {
  5223. pSprite->z = z++;
  5224. }
  5225. }
  5226. /******************************Public*Routine******************************\
  5227. * VOID vSpDeleteSprite
  5228. *
  5229. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5230. * Wrote it.
  5231. \**************************************************************************/
  5232. VOID vSpDeleteSprite(
  5233. SPRITE* pSprite)
  5234. {
  5235. SPRITESTATE* pState;
  5236. BOOL bRet;
  5237. SPRITE* pTmp;
  5238. SPRITE* pNext;
  5239. SPRITE* pPrevious;
  5240. if (pSprite == NULL)
  5241. return;
  5242. pState = pSprite->pState;
  5243. PDEVOBJ po(pState->hdev);
  5244. DEVLOCKOBJ dlo(po);
  5245. SPRITELOCK slock(po);
  5246. // Hide the sprite:
  5247. bRet = bSpUpdatePosition(pSprite, NULL);
  5248. ASSERTGDI(bRet, "vSpDeleteSprite: hide failed");
  5249. #if DEBUG_SPRITES
  5250. vSpValidateVisibleSprites(pState);
  5251. #endif
  5252. // Remove the sprite from the z-sorted linked list:
  5253. if (pState->pListZ == pSprite)
  5254. {
  5255. pState->pListZ = pSprite->pNextZ;
  5256. }
  5257. else
  5258. {
  5259. for (pTmp = pState->pListZ; pTmp != NULL; pTmp = pTmp->pNextZ)
  5260. {
  5261. if (pTmp->pNextZ == pSprite)
  5262. {
  5263. pTmp->pNextZ = pSprite->pNextZ;
  5264. break;
  5265. }
  5266. }
  5267. }
  5268. // Delete the sprite from the Y-sorted linked list:
  5269. pPrevious = pSprite->pPreviousY;
  5270. pNext = pSprite->pNextY;
  5271. if (pNext)
  5272. pNext->pPreviousY = pPrevious;
  5273. if (pPrevious)
  5274. pPrevious->pNextY = pNext;
  5275. else
  5276. {
  5277. ASSERTGDI(pState->pListY == pSprite, "Expected top of list");
  5278. pState->pListY = pNext;
  5279. }
  5280. // Free all allocated data associated with this sprite:
  5281. vSpFreeClipResources(pSprite);
  5282. vSpDeleteShape(pSprite);
  5283. vSpDeleteSurface(pSprite->psoUnderlay);
  5284. if (pSprite->psoMask != NULL)
  5285. {
  5286. bDeleteSurface(pSprite->psoMask->hsurf);
  5287. pSprite->psoMask = NULL;
  5288. }
  5289. // Take this as an opportunity to free the compositing surface:
  5290. vSpDeleteSurface(pState->psoComposite);
  5291. pState->psoComposite = NULL;
  5292. // We're all done with this object, so free the memory and
  5293. // leave:
  5294. VFREEMEM(pSprite);
  5295. }
  5296. /******************************Public*Routine******************************\
  5297. * SPRITE* pSpCreateSprite
  5298. *
  5299. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5300. * Wrote it.
  5301. \**************************************************************************/
  5302. SPRITE* pSpCreateSprite(
  5303. HDEV hdev,
  5304. RECTL* prcl,
  5305. HWND hwnd,
  5306. POINTL* pptlDstInit=NULL)
  5307. {
  5308. SPRITE* pSprite;
  5309. SPRITE* pPrevious;
  5310. SPRITE* pNext;
  5311. SPRITE* pTarget;
  5312. pSprite = NULL; // Assume failure
  5313. PDEVOBJ po(hdev);
  5314. if (po.bDisplayPDEV())
  5315. {
  5316. DEVLOCKOBJ dlo(po);
  5317. SPRITELOCK slock(po);
  5318. SPRITESTATE* pState = po.pSpriteState();
  5319. pSprite = (SPRITE*) PALLOCMEM(sizeof(SPRITE), ' psG');
  5320. if (pSprite != NULL)
  5321. {
  5322. if (prcl != NULL)
  5323. {
  5324. pSprite->sizlHint.cx = prcl->right - prcl->left;
  5325. pSprite->sizlHint.cy = prcl->bottom - prcl->top;
  5326. pSprite->ptlDst.x =
  5327. pptlDstInit ? pptlDstInit->x : prcl->left;
  5328. pSprite->ptlDst.y =
  5329. pptlDstInit ? pptlDstInit->y : prcl->top;
  5330. }
  5331. else
  5332. {
  5333. pSprite->sizlHint.cx = 0;
  5334. pSprite->sizlHint.cy = 0;
  5335. pSprite->ptlDst.x = LONG_MIN;
  5336. pSprite->ptlDst.y = LONG_MIN;
  5337. }
  5338. pSprite->fl = 0;
  5339. pSprite->pState = pState;
  5340. pSprite->dwShape = ULW_OPAQUE;
  5341. pSprite->rclSprite.top = LONG_MIN;
  5342. pSprite->rclSprite.left = LONG_MIN;
  5343. pSprite->rclSprite.bottom = LONG_MIN;
  5344. pSprite->rclSprite.right = LONG_MIN;
  5345. #if DEBUG_SPRITES
  5346. pSprite->pNextVisible = NULL;
  5347. #endif
  5348. // Add this sprite to the end of the z-list, meaning that
  5349. // it will be top-most. Well, top-most except for the
  5350. // cursor sprites:
  5351. pTarget = pState->pBottomCursor;
  5352. if (pState->pListZ == pTarget)
  5353. {
  5354. pSprite->pNextZ = pTarget;
  5355. pState->pListZ = pSprite;
  5356. }
  5357. else
  5358. {
  5359. for (pPrevious = pState->pListZ;
  5360. pPrevious->pNextZ != pTarget;
  5361. pPrevious = pPrevious->pNextZ)
  5362. ;
  5363. pSprite->pNextZ = pTarget;
  5364. pPrevious->pNextZ = pSprite;
  5365. }
  5366. vSpRenumberZOrder(pState);
  5367. // Add this sprite to the front of the y-list.
  5368. // pSprite->pPreviousY was already zero-initialized:
  5369. pNext = pState->pListY;
  5370. pState->pListY = pSprite;
  5371. pSprite->pNextY = pNext;
  5372. if (pNext)
  5373. pNext->pPreviousY = pSprite;
  5374. pSprite->hwnd = hwnd;
  5375. vSpOrderInY(pSprite);
  5376. }
  5377. }
  5378. return(pSprite);
  5379. }
  5380. /******************************Public*Routine******************************\
  5381. * BOOL bSpEnableSprites
  5382. *
  5383. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5384. * Wrote it.
  5385. \**************************************************************************/
  5386. BOOL bSpEnableSprites(
  5387. HDEV hdev)
  5388. {
  5389. SPRITESTATE* pState;
  5390. CLIPOBJ* pco;
  5391. SPRITESCAN* pRange;
  5392. SIZEL sizl;
  5393. HSURF hsurf;
  5394. SURFACE* psurfScreen;
  5395. SURFOBJ* psoHitTest;
  5396. PDEVOBJ po(hdev);
  5397. if (!po.bDisplayPDEV())
  5398. return(TRUE);
  5399. psurfScreen = SURFOBJ_TO_SURFACE_NOT_NULL(po.pSurface()->pSurfobj());
  5400. pState = po.pSpriteState();
  5401. // Remember some information about the current mode:
  5402. pState->hdev = hdev;
  5403. pState->psoScreen = psurfScreen->pSurfobj();
  5404. pState->iModeFormat = psurfScreen->iFormat();
  5405. pState->iOriginalType = psurfScreen->iType();
  5406. pState->flOriginalSurfFlags = psurfScreen->flags();
  5407. pState->iSpriteType = pState->iOriginalType;
  5408. pState->flSpriteSurfFlags = pState->flOriginalSurfFlags;
  5409. XEPALOBJ pal(psurfScreen->ppal());
  5410. pState->flModeMasks = pal.flRed() | pal.flBlu();
  5411. // Initialize the screen size:
  5412. pState->rclScreen.left = 0;
  5413. pState->rclScreen.right = psurfScreen->sizl().cx;
  5414. pState->rclScreen.top = 0;
  5415. pState->rclScreen.bottom = psurfScreen->sizl().cy;
  5416. // Now allocate some regions that we'll use later:
  5417. RGNMEMOBJ rmoUncovered;
  5418. RGNMEMOBJ rmoTmp;
  5419. RGNMEMOBJ rmoRectangular;
  5420. if (rmoUncovered.bValid() && rmoTmp.bValid() && rmoRectangular.bValid())
  5421. {
  5422. pRange = (SPRITESCAN*) PALLOCMEM(sizeof(SPRITESCAN), 'rpsG');
  5423. if (pRange)
  5424. {
  5425. // TRUE to denote that we want an STYPE_BITMAP surface, because
  5426. // we have to be able to access the bits directly for hit testing:
  5427. psoHitTest = psoSpCreateSurface(pState, 0, 1, 1, TRUE);
  5428. if (psoHitTest)
  5429. {
  5430. // Mark the surface, so that it can be special-cased by
  5431. // the dynamic mode change code:
  5432. vSpSetNullRange(pState, pRange);
  5433. pState->psoHitTest = psoHitTest;
  5434. // We need a DC_RECT clip object:
  5435. rmoRectangular.vSet(&pState->rclScreen);
  5436. pState->prgnRectangular = rmoRectangular.prgnGet();
  5437. pState->coRectangular.vSetup(rmoRectangular.prgnGet(),
  5438. *((ERECTL*) &pState->rclScreen),
  5439. CLIP_FORCE);
  5440. pState->prgnUncovered = rmoUncovered.prgnGet();
  5441. pState->prgnUncovered->vStamp();
  5442. pState->prgnTmp = rmoTmp.prgnGet();
  5443. pState->hrgn = GreCreateRectRgn(0, 0, 0, 0);
  5444. // Save some hook state:
  5445. pState->pfnStrokePath = PPFNDRV(po, StrokePath);
  5446. pState->pfnFillPath = PPFNDRV(po, FillPath);
  5447. pState->pfnBitBlt = PPFNDRV(po, BitBlt);
  5448. pState->pfnCopyBits = PPFNDRV(po, CopyBits);
  5449. pState->pfnStretchBlt = PPFNDRV(po, StretchBlt);
  5450. pState->pfnTextOut = PPFNDRV(po, TextOut);
  5451. pState->pfnLineTo = PPFNDRV(po, LineTo);
  5452. pState->pfnTransparentBlt = PPFNDRV(po, TransparentBlt);
  5453. pState->pfnAlphaBlend = PPFNDRV(po, AlphaBlend);
  5454. pState->pfnPlgBlt = PPFNDRV(po, PlgBlt);
  5455. pState->pfnGradientFill = PPFNDRV(po, GradientFill);
  5456. pState->pfnStretchBltROP = PPFNDRV(po, StretchBltROP);
  5457. pState->pfnSaveScreenBits = PPFNDRV(po, SaveScreenBits);
  5458. pState->pfnDrawStream = PPFNDRV(po, DrawStream);
  5459. return(TRUE);
  5460. }
  5461. VFREEMEM(pRange);
  5462. }
  5463. }
  5464. WARNING("bSpEnableSprites: Failed!");
  5465. rmoUncovered.vDeleteRGNOBJ();
  5466. rmoTmp.vDeleteRGNOBJ();
  5467. rmoRectangular.vDeleteRGNOBJ();
  5468. return(FALSE);
  5469. }
  5470. /******************************Public*Routine******************************\
  5471. * VOID vSpDisableSprites
  5472. *
  5473. * Called when the device's surface is about to be destroyed.
  5474. *
  5475. * Note: This function may be called without bDdEnableSprites having
  5476. * first been called!
  5477. *
  5478. * Note that this may be called for printers and the like.
  5479. *
  5480. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5481. * Wrote it.
  5482. \**************************************************************************/
  5483. VOID vSpDisableSprites(
  5484. HDEV hdev,
  5485. CLEANUPTYPE cutype)
  5486. {
  5487. SPRITESTATE* pState;
  5488. PDEVOBJ po(hdev);
  5489. pState = po.pSpriteState();
  5490. SPRITE* pSprite = pState->pBottomCursor;
  5491. while(pSprite != NULL)
  5492. {
  5493. SPRITE* pNextSprite = pSprite->pNextZ;
  5494. vSpDeleteSprite(pSprite);
  5495. pSprite = pNextSprite;
  5496. }
  5497. pState->pTopCursor = NULL;
  5498. pState->pBottomCursor = NULL;
  5499. pState->ulNumCursors = 0;
  5500. ASSERTGDI(pState->pListZ == NULL, "Expected to have 0 sprites");
  5501. ASSERTGDI(pState->psoComposite == NULL, "Expected no composite surface");
  5502. // During session cleanup (i.e., hydra shutdown), surfaces are
  5503. // deleted as part of the HMGR object cleanup. So we can skip
  5504. // this for CLEANUP_SESSION:
  5505. if (cutype != CLEANUP_SESSION)
  5506. {
  5507. vSpDeleteSurface(pState->psoHitTest);
  5508. }
  5509. // These regions, on the other hand, are not in the HMGR so
  5510. // must be cleaned up always:
  5511. RGNOBJ roUncovered(pState->prgnUncovered);
  5512. RGNOBJ roTmp(pState->prgnTmp);
  5513. RGNOBJ roRectangular(pState->prgnRectangular);
  5514. roUncovered.vDeleteRGNOBJ();
  5515. roTmp.vDeleteRGNOBJ();
  5516. roRectangular.vDeleteRGNOBJ();
  5517. // Since we are referencing this region by handle, it is safe
  5518. // to do even during session cleanup:
  5519. GreDeleteObject(pState->hrgn);
  5520. if (pState->pRange)
  5521. {
  5522. VFREEMEM(pState->pRange);
  5523. }
  5524. if (pState->ahdevMultiMon)
  5525. {
  5526. EngFreeMem(pState->ahdevMultiMon);
  5527. }
  5528. if (pState->prgnUnlocked != NULL)
  5529. {
  5530. pState->prgnUnlocked->vDeleteREGION();
  5531. }
  5532. // Leave the sprite state in the PDEV in a newly initialized state:
  5533. RtlZeroMemory(pState, sizeof(*pState));
  5534. }
  5535. /******************************Public*Routine******************************\
  5536. * VOID vSpEnableMultiMon
  5537. *
  5538. * This routine is called by the multi-mon code to let us know the children
  5539. * of a multi-mon meta PDEV.
  5540. *
  5541. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5542. * Wrote it.
  5543. \**************************************************************************/
  5544. VOID vSpEnableMultiMon(
  5545. HDEV hdev,
  5546. ULONG c,
  5547. HDEV* ahdev) // Must be allocated by the caller and freed
  5548. { // by calling vSpDisableMultiMon
  5549. SPRITESTATE* pState;
  5550. PDEVOBJ po(hdev);
  5551. pState = po.pSpriteState();
  5552. pState->cMultiMon = c;
  5553. pState->ahdevMultiMon = ahdev;
  5554. }
  5555. /******************************Public*Routine******************************\
  5556. * VOID vSpDisableMultiMon
  5557. *
  5558. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5559. * Wrote it.
  5560. \**************************************************************************/
  5561. VOID vSpDisableMultiMon(
  5562. HDEV hdev)
  5563. {
  5564. SPRITESTATE* pState;
  5565. PDEVOBJ po(hdev);
  5566. pState = po.pSpriteState();
  5567. if (pState->ahdevMultiMon)
  5568. {
  5569. VFREEMEM(pState->ahdevMultiMon);
  5570. }
  5571. pState->cMultiMon = 0;
  5572. pState->ahdevMultiMon = NULL;
  5573. ASSERTGDI(pState->pListMeta == NULL, "Expected no meta-sprites");
  5574. }
  5575. /******************************Public*Routine******************************\
  5576. * VOID vSpHideSprites
  5577. *
  5578. * Hides or unhides all sprites on a PDEV and all of its child PDEVs.
  5579. *
  5580. * 1-Mar-2001 -by- Jason Hartman [jasonha]
  5581. * Wrote it.
  5582. \**************************************************************************/
  5583. VOID
  5584. vSpHideSprites(
  5585. HDEV hdev,
  5586. BOOL bHide
  5587. )
  5588. {
  5589. GDIFunctionID(vSpHideSprites);
  5590. PDEVOBJ po(hdev);
  5591. SPRITELOCK slock(po);
  5592. SPRITESTATE* pState;
  5593. pState = po.pSpriteState();
  5594. if (pState->cMultiMon)
  5595. {
  5596. ULONG i;
  5597. for (i = 0; i < pState->cMultiMon; i++)
  5598. {
  5599. vSpHideSprites(pState->ahdevMultiMon[i], bHide);
  5600. }
  5601. }
  5602. else
  5603. {
  5604. SPRITE* pSprite = pState->pListZ;
  5605. while (pSprite != NULL)
  5606. {
  5607. SPRITE* pNextSprite = pSprite->pNextZ;
  5608. if (bHide)
  5609. {
  5610. ASSERTGDI((pSprite->fl & SPRITE_FLAG_HIDDEN) == 0, "Sprite is already hidden.");
  5611. pSprite->fl |= SPRITE_FLAG_HIDDEN;
  5612. }
  5613. else
  5614. {
  5615. ASSERTGDI((pSprite->fl & SPRITE_FLAG_HIDDEN) != 0, "Sprite is not hidden.");
  5616. pSprite->fl &= ~SPRITE_FLAG_HIDDEN;
  5617. }
  5618. bSpUpdatePosition(pSprite, &pSprite->ptlDst);
  5619. pSprite = pNextSprite;
  5620. }
  5621. }
  5622. if (bHide)
  5623. {
  5624. ASSERTGDI(pState->cVisible == 0, "Sprites remain visible after we hid them all.");
  5625. ASSERTGDI(!pState->bHooked, "Sprite layer remains hooked after we hid all sprites.");
  5626. }
  5627. }
  5628. /******************************Public*Routine******************************\
  5629. * SPRITE* pSpTransferSprite
  5630. *
  5631. * Transfers a sprite to a new PDEV by creating a new sprite that copies
  5632. * the contents of the old, and then deleting the old sprite.
  5633. *
  5634. * NOTE: pSpriteOld is freed by this function, so it must not be accessed
  5635. * after calling!
  5636. *
  5637. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5638. * Wrote it.
  5639. \**************************************************************************/
  5640. SPRITE* pSpTransferSprite(
  5641. HDEV hdevNew,
  5642. SPRITE* pSpriteOld)
  5643. {
  5644. SPRITE* pSpriteNew;
  5645. POINTL ptlZero;
  5646. pSpriteNew = NULL;
  5647. if (pSpriteOld->hwnd == NULL)
  5648. {
  5649. // There shouldn't be any non-hwnd associated sprites at this point.
  5650. ASSERTGDI(FALSE,
  5651. "pSpTransferSprite: pSpriteOld is not hwnd associated!");
  5652. }
  5653. else
  5654. {
  5655. pSpriteNew = pSpCreateSprite(hdevNew,
  5656. NULL,
  5657. pSpriteOld->hwnd);
  5658. if (pSpriteNew)
  5659. {
  5660. vSpTransferShape(pSpriteNew, pSpriteOld);
  5661. if (!bSpUpdatePosition(pSpriteNew,
  5662. &pSpriteOld->ptlDst))
  5663. {
  5664. vSpDeleteSprite(pSpriteNew);
  5665. pSpriteNew = NULL;
  5666. }
  5667. else
  5668. {
  5669. // If this sprite is a part of Meta Sprite,
  5670. // update Meta Sprite, too.
  5671. if (pSpriteOld->pMetaSprite != NULL)
  5672. {
  5673. METASPRITE *pMetaSprite = pSpriteOld->pMetaSprite;
  5674. BOOL bSpriteInMeta = FALSE;
  5675. for (ULONG i = 0; i < pMetaSprite->chSprite; i++)
  5676. {
  5677. if (pMetaSprite->apSprite[i] == pSpriteOld)
  5678. {
  5679. pMetaSprite->apSprite[i] = pSpriteNew;
  5680. pSpriteNew->pMetaSprite = pMetaSprite;
  5681. if (bSpriteInMeta)
  5682. {
  5683. WARNING("pSpTransferSprite: Sprite in meta multiple times!");
  5684. }
  5685. bSpriteInMeta = TRUE;
  5686. }
  5687. }
  5688. if (!bSpriteInMeta)
  5689. {
  5690. WARNING("pSpTransferSprite: No sprite in meta!");
  5691. }
  5692. }
  5693. }
  5694. }
  5695. }
  5696. // If new sprite could not be created, the metasprite is still pointing
  5697. // to the old sprite which we are about to delete.
  5698. if (!pSpriteNew && (pSpriteOld->pMetaSprite != NULL))
  5699. {
  5700. METASPRITE *pMetaSprite = pSpriteOld->pMetaSprite;
  5701. // Mark the meta sprite for deletion. This is because the call to
  5702. // UserRemoveRedirectionBitmap will unset the layered flag on the
  5703. // window and so user will not attempt to delete the sprite in the
  5704. // futue (i.e. if we don't do this we will leak memory). The actual
  5705. // deletion will happen in pSpTransferMetaSprite.
  5706. pMetaSprite->fl |= SPRITE_FLAG_NO_WINDOW;
  5707. for (ULONG i = 0; i < pMetaSprite->chSprite; i++)
  5708. {
  5709. if (pMetaSprite->apSprite[i] == pSpriteOld)
  5710. {
  5711. pMetaSprite->apSprite[i] = NULL;
  5712. }
  5713. }
  5714. }
  5715. vSpDeleteSprite(pSpriteOld);
  5716. return(pSpriteNew);
  5717. }
  5718. /******************************Public*Routine******************************\
  5719. * VOID vSpCorrectHdevReferences
  5720. *
  5721. * On a dynamic mode change, sprite state is transferred between the two
  5722. * PDEVs along with the rest of the driver state. As such, we have to
  5723. * go back through and correct any references to the old HDEV.
  5724. *
  5725. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  5726. * Wrote it.
  5727. \**************************************************************************/
  5728. VOID vSpCorrectHdevReferences(
  5729. SPRITESTATE* pState,
  5730. HDEV hdev)
  5731. {
  5732. SPRITE* pSprite;
  5733. pState->hdev = hdev;
  5734. // Note that any surfaces created by psoSpCreateSurface are tagged
  5735. // as sprite surfaces, and left alone by bDynamicModeChange, so that
  5736. // we can handle them here.
  5737. if (pState->psoComposite != NULL)
  5738. pState->psoComposite->hdev = hdev;
  5739. if (pState->psoHitTest != NULL)
  5740. pState->psoHitTest->hdev = hdev;
  5741. for (pSprite = pState->pListZ;
  5742. pSprite != NULL;
  5743. pSprite = pSprite->pNextZ)
  5744. {
  5745. pSprite->pState = pState;
  5746. if (pSprite->psoShape != NULL)
  5747. {
  5748. ASSERTGDI(pSprite->psoShape->hdev != 0,
  5749. "Didn't expect NULL shape hdev");
  5750. pSprite->psoShape->hdev = hdev;
  5751. }
  5752. if (pSprite->psoUnderlay != NULL)
  5753. {
  5754. ASSERTGDI(pSprite->psoUnderlay->hdev != 0,
  5755. "Didn't expect NULL shape hdev");
  5756. pSprite->psoUnderlay->hdev = hdev;
  5757. }
  5758. }
  5759. }
  5760. /******************************Public*Routine******************************\
  5761. * METASPRITE* pSpConvertSpriteToMeta
  5762. *
  5763. * On a dynamic mode change, sprite state is transferred between the meta-PDEV
  5764. * and device PDEV along with the rest of the driver state. As such, we have
  5765. * to convert "sprite" to "meta sprite" when 1 monitor to multi-monitors mode
  5766. * change
  5767. *
  5768. * 2-Jul-1998 -by- Hideyuki Nagase [hideyukn]
  5769. * Wrote it.
  5770. \**************************************************************************/
  5771. METASPRITE* pSpConvertSpriteToMeta(
  5772. HDEV hdevMetaNew,
  5773. HDEV hdevDevOld,
  5774. SPRITE* pSpriteOld)
  5775. {
  5776. METASPRITE *pMetaSpriteNew;
  5777. SPRITE *pSpriteNew;
  5778. SPRITESTATE *pState;
  5779. BOOL bError = FALSE;
  5780. pMetaSpriteNew = NULL;
  5781. if (pSpriteOld->hwnd == NULL)
  5782. {
  5783. // There shouldn't be any non-hwnd associated sprites at this point.
  5784. ASSERTGDI(FALSE,
  5785. "pSpConvertSpriteToMeta: pSpriteOld is not hwnd associated!");
  5786. }
  5787. else
  5788. {
  5789. PDEVOBJ poMeta(hdevMetaNew);
  5790. // When running multi-mon, handle the creation of the meta sprite:
  5791. pState = poMeta.pSpriteState();
  5792. if (pState->cMultiMon)
  5793. {
  5794. // Create MetaSprites and 'real' sprites for children.
  5795. ULONG cjAlloc = sizeof(METASPRITE)
  5796. + pState->cMultiMon
  5797. * sizeof(pMetaSpriteNew->apSprite[0]);
  5798. pMetaSpriteNew = (METASPRITE*) PALLOCNOZ(cjAlloc, 'mpsG');
  5799. if (pMetaSpriteNew)
  5800. {
  5801. for (ULONG i = 0; i < pState->cMultiMon; i++)
  5802. {
  5803. PDEVOBJ poDevice(pState->ahdevMultiMon[i]);
  5804. SPRITELOCK slock(poDevice);
  5805. pSpriteNew = pSpCreateSprite(poDevice.hdev(),
  5806. NULL,
  5807. pSpriteOld->hwnd);
  5808. if (pSpriteNew)
  5809. {
  5810. POINTL ptlDst;
  5811. PDEVOBJ poDevOld(hdevDevOld);
  5812. // Transfer the information from old sprite
  5813. // to new sprite.
  5814. vSpTransferShape(pSpriteNew, pSpriteOld);
  5815. // The sprite position need to be adjusted based on
  5816. // poDevice origin, since we switch to multi-monitor
  5817. // system, and then poDevice origion might not be equal
  5818. // poDevOld.
  5819. // poDevOld coordinate to meta coordinate
  5820. ptlDst.x =
  5821. pSpriteOld->ptlDst.x + poDevOld.pptlOrigin()->x;
  5822. ptlDst.y =
  5823. pSpriteOld->ptlDst.y + poDevOld.pptlOrigin()->y;
  5824. // meta coordinate to poDevice coordinate
  5825. ptlDst.x -= poDevice.pptlOrigin()->x;
  5826. ptlDst.y -= poDevice.pptlOrigin()->y;
  5827. if (bSpUpdatePosition(pSpriteNew, &ptlDst))
  5828. {
  5829. pMetaSpriteNew->apSprite[i] = pSpriteNew;
  5830. pSpriteNew->pMetaSprite = pMetaSpriteNew;
  5831. }
  5832. else
  5833. {
  5834. vSpDeleteSprite(pSpriteNew);
  5835. bError = TRUE;
  5836. break;
  5837. }
  5838. }
  5839. else
  5840. {
  5841. bError = TRUE;
  5842. break;
  5843. }
  5844. }
  5845. if (bError)
  5846. {
  5847. for (; i > 0; i--)
  5848. {
  5849. vSpDeleteSprite(pMetaSpriteNew->apSprite[i - 1]);
  5850. }
  5851. VFREEMEM(pMetaSpriteNew);
  5852. // Set this to NULL so we don't write on it later.
  5853. // This fixes the logic below
  5854. pMetaSpriteNew = NULL;
  5855. }
  5856. else
  5857. {
  5858. pMetaSpriteNew->hwnd = pSpriteOld->hwnd;
  5859. pMetaSpriteNew->chSprite = pState->cMultiMon;
  5860. pMetaSpriteNew->fl = 0;
  5861. // Add this node to the head of the meta-sprite list:
  5862. pMetaSpriteNew->pNext = pState->pListMeta;
  5863. pState->pListMeta = pMetaSpriteNew;
  5864. }
  5865. }
  5866. }
  5867. else
  5868. {
  5869. WARNING("pSpConvertSpriteToMeta(): cMultiMon is 0\n");
  5870. }
  5871. }
  5872. // Delete old sprite
  5873. vSpDeleteSprite(pSpriteOld);
  5874. return(pMetaSpriteNew);
  5875. }
  5876. /******************************Public*Routine******************************\
  5877. * SPRITE* pSpConvertSpriteFromMeta
  5878. *
  5879. * On a dynamic mode change, sprite state is transferred between the meta-PDEV
  5880. * and device PDEV along with the rest of the driver state. As such, we have
  5881. * to convert "meta sprite" to "sprite" when multi-monitors to 1 monitor mode
  5882. * change
  5883. *
  5884. * 2-Jul-1998 -by- Hideyuki Nagase [hideyukn]
  5885. * Wrote it.
  5886. \**************************************************************************/
  5887. SPRITE* pSpConvertSpriteFromMeta(
  5888. HDEV hdevDevNew,
  5889. HDEV hdevMetaOld,
  5890. METASPRITE* pMetaSpriteOld)
  5891. {
  5892. SPRITE* pSpriteNew;
  5893. SPRITE* pSpriteOld;
  5894. SPRITESTATE *pStateMeta;
  5895. ULONG i;
  5896. PDEVOBJ poMeta(hdevMetaOld);
  5897. pSpriteNew = NULL;
  5898. pStateMeta = poMeta.pSpriteState();
  5899. if (pMetaSpriteOld->hwnd == NULL)
  5900. {
  5901. // There shouldn't be any non-hwnd associated sprites at this point.
  5902. ASSERTGDI(FALSE,
  5903. "pSpConvertSpriteFromMeta: pSpriteOld is not hwnd associated!");
  5904. }
  5905. else
  5906. {
  5907. pSpriteOld = NULL;
  5908. // Find a the sprite lives in PDEV which has highest color
  5909. // depth, remember this for transfering shape for new
  5910. // sprite.
  5911. ULONG iDitherHighest = 0;
  5912. for (i = 0; i < pMetaSpriteOld->chSprite; i++)
  5913. {
  5914. SPRITE* pSpriteTmp = pMetaSpriteOld->apSprite[i];
  5915. if (pSpriteTmp)
  5916. {
  5917. PDEVOBJ poTmp(pSpriteTmp->pState->hdev);
  5918. if (iDitherHighest < poTmp.iDitherFormat())
  5919. {
  5920. pSpriteOld = pSpriteTmp;
  5921. iDitherHighest = poTmp.iDitherFormat();
  5922. }
  5923. }
  5924. }
  5925. // Convert sprite on old hdev to new hdev.
  5926. if (pSpriteOld)
  5927. {
  5928. pSpriteNew = pSpCreateSprite(hdevDevNew,
  5929. NULL,
  5930. pMetaSpriteOld->hwnd);
  5931. if (pSpriteNew)
  5932. {
  5933. vSpTransferShape(pSpriteNew, pSpriteOld);
  5934. // The sprite position needs to be adjusted based on
  5935. // origin of the old PDEV
  5936. PDEVOBJ poOld(pSpriteOld->pState->hdev);
  5937. EPOINTL ptlSpritePos = pSpriteOld->ptlDst;
  5938. ptlSpritePos += *(poOld.pptlOrigin());
  5939. if (!bSpUpdatePosition(pSpriteNew,
  5940. &ptlSpritePos))
  5941. {
  5942. vSpDeleteSprite(pSpriteNew);
  5943. pSpriteNew = NULL;
  5944. }
  5945. }
  5946. }
  5947. }
  5948. // Delete old sprites on meta sprite.
  5949. for (i = 0; i < pMetaSpriteOld->chSprite; i++)
  5950. {
  5951. vSpDeleteSprite(pMetaSpriteOld->apSprite[i]);
  5952. }
  5953. // Remove this meta sprite from the linked list :
  5954. if (pStateMeta->pListMeta == pMetaSpriteOld)
  5955. {
  5956. pStateMeta->pListMeta = pMetaSpriteOld->pNext;
  5957. }
  5958. else
  5959. {
  5960. for (METASPRITE *pTmp = pStateMeta->pListMeta;
  5961. pTmp->pNext != pMetaSpriteOld;
  5962. pTmp = pTmp->pNext)
  5963. ;
  5964. pTmp->pNext = pMetaSpriteOld->pNext;
  5965. }
  5966. // Delete meta sprite.
  5967. VFREEMEM(pMetaSpriteOld);
  5968. return(pSpriteNew);
  5969. }
  5970. /******************************Public*Routine******************************\
  5971. * METASPRITE* pSpMoveSpriteFromMeta
  5972. *
  5973. * 1-Sep-1998 -by- Hideyuki Nagase [hideyukn]
  5974. * Wrote it.
  5975. \**************************************************************************/
  5976. SPRITE* pSpMoveSpriteFromMeta(
  5977. HDEV hdevDevNew,
  5978. HDEV hdevMetaOld,
  5979. METASPRITE* pMetaSpriteOld,
  5980. ULONG ulIndex)
  5981. {
  5982. ULONG i;
  5983. SPRITE* pSpriteOrg;
  5984. SPRITE* pSpriteNew = NULL;
  5985. SPRITESTATE* pStateMeta;
  5986. PDEVOBJ poDev(hdevDevNew);
  5987. PDEVOBJ poMeta(hdevMetaOld);
  5988. pStateMeta = poMeta.pSpriteState();
  5989. // Pick up the sprite we may reuse.
  5990. pSpriteOrg = pMetaSpriteOld->apSprite[ulIndex];
  5991. if (pSpriteOrg)
  5992. {
  5993. // Make sure the sprite belonging to device specific HDEV,
  5994. // actually under DDI. the sprite already lives this DHPDEV.
  5995. ASSERTGDI(pSpriteOrg->pState == poDev.pSpriteState(),
  5996. "ERROR: pState does not points device PDEV");
  5997. // And this sprite no longer has meta sprite, the meta sprite
  5998. // will be deleted in below.
  5999. pSpriteOrg->pMetaSprite = NULL;
  6000. }
  6001. if (pMetaSpriteOld->hwnd == NULL)
  6002. {
  6003. // There shouldn't be any non-hwnd associated sprites at this point.
  6004. ASSERTGDI(FALSE,
  6005. "pSpMoveSpriteFromMeta: pSpriteOld is not hwnd associated!");
  6006. }
  6007. else
  6008. {
  6009. pSpriteNew = pSpriteOrg;
  6010. }
  6011. // Delete old sprites on meta sprite.
  6012. for (i = 0; i < pMetaSpriteOld->chSprite; i++)
  6013. {
  6014. if ((i != ulIndex) || (pSpriteNew == NULL))
  6015. {
  6016. vSpDeleteSprite(pMetaSpriteOld->apSprite[i]);
  6017. }
  6018. }
  6019. // Remove this meta sprite from the linked list :
  6020. if (pStateMeta->pListMeta == pMetaSpriteOld)
  6021. {
  6022. pStateMeta->pListMeta = pMetaSpriteOld->pNext;
  6023. }
  6024. else
  6025. {
  6026. for (METASPRITE *pTmp = pStateMeta->pListMeta;
  6027. pTmp->pNext != pMetaSpriteOld;
  6028. pTmp = pTmp->pNext)
  6029. ;
  6030. pTmp->pNext = pMetaSpriteOld->pNext;
  6031. }
  6032. // Delete meta sprite.
  6033. VFREEMEM(pMetaSpriteOld);
  6034. return(pSpriteNew);
  6035. }
  6036. /******************************Public*Routine******************************\
  6037. * METASPRITE* pSpTransferMetaSprite
  6038. *
  6039. * 30-Aug-1998 -by- Hideyuki Nagase [hideyukn]
  6040. * Wrote it.
  6041. \**************************************************************************/
  6042. METASPRITE* pSpTransferMetaSprite(
  6043. HDEV hdevNew,
  6044. HDEV hdevOld,
  6045. METASPRITE* pMetaSpriteOld)
  6046. {
  6047. SPRITESTATE* pStateNew;
  6048. SPRITESTATE* pStateOld;
  6049. METASPRITE* pMetaSpriteNew;
  6050. SPRITE* pSprite;
  6051. ULONG i, j;
  6052. BOOL bError = FALSE;
  6053. PDEVOBJ poNew(hdevNew);
  6054. PDEVOBJ poOld(hdevOld);
  6055. pStateNew = poNew.pSpriteState();
  6056. pStateOld = poOld.pSpriteState();
  6057. if (pMetaSpriteOld->hwnd == NULL)
  6058. {
  6059. // There shouldn't be any non-hwnd associated sprites at this point.
  6060. ASSERTGDI(FALSE,
  6061. "pSpTransferMetaSprite: pSpriteOld is not hwnd associated!");
  6062. }
  6063. else
  6064. {
  6065. // Create METASPRITE on new hdev.
  6066. ULONG cjAlloc = sizeof(METASPRITE)
  6067. + pStateNew->cMultiMon
  6068. * sizeof(pMetaSpriteNew->apSprite[0]);
  6069. if (pMetaSpriteOld->fl & SPRITE_FLAG_NO_WINDOW)
  6070. {
  6071. // If the metasprite is marked for deletion, don't reallocate a new
  6072. // metasprite. The cleanup code below will make sure the old
  6073. // metasprite and its child sprites are deleted.
  6074. pMetaSpriteNew = NULL;
  6075. }
  6076. else
  6077. {
  6078. pMetaSpriteNew = (METASPRITE*) PALLOCMEM(cjAlloc, 'mpsG');
  6079. }
  6080. if (pMetaSpriteNew)
  6081. {
  6082. SPRITE *pSpriteBest = NULL;
  6083. HDEV hdevBest = NULL;
  6084. ULONG iFormatBest = 0;
  6085. // Transfer sprite from old meta to new as much as possible.
  6086. for (i = 0 ; i < pStateNew->cMultiMon ; i++)
  6087. {
  6088. for (j = 0; j < pMetaSpriteOld->chSprite ; j++)
  6089. {
  6090. pSprite = pMetaSpriteOld->apSprite[j];
  6091. if (pSprite)
  6092. {
  6093. PDEVOBJ poTmp(pSprite->pState->hdev);
  6094. // if pointer to pState is same, we can transfer
  6095. // to new pdev.
  6096. if (pStateNew == pSprite->pState)
  6097. {
  6098. // move this sprite to new meta sprite from old.
  6099. pMetaSpriteNew->apSprite[i] = pSprite;
  6100. pMetaSpriteOld->apSprite[j] = NULL;
  6101. pSprite->pMetaSprite = pMetaSpriteNew;
  6102. }
  6103. // if the sprite lives in PDEV which has higher color
  6104. // depth, remember this for transfering shape for new
  6105. // sprite
  6106. if (iFormatBest < poTmp.iDitherFormat())
  6107. {
  6108. pSpriteBest = pSprite;
  6109. hdevBest = poTmp.hdev();
  6110. iFormatBest = poTmp.iDitherFormat();
  6111. }
  6112. }
  6113. }
  6114. }
  6115. // fill up other meta sprite fields
  6116. pMetaSpriteNew->hwnd = pMetaSpriteOld->hwnd;
  6117. pMetaSpriteNew->chSprite = pStateNew->cMultiMon;
  6118. pMetaSpriteNew->fl = 0;
  6119. // if there is any sprite which can not be trasnferred from old,
  6120. // create them
  6121. for (i = 0 ; i < pMetaSpriteNew->chSprite ; i++)
  6122. {
  6123. if (pMetaSpriteNew->apSprite[i] == NULL)
  6124. {
  6125. PDEVOBJ poDevice(pStateNew->ahdevMultiMon[i]);
  6126. SPRITELOCK slockDevice(poDevice);
  6127. pSprite= pSpCreateSprite(poDevice.hdev(),
  6128. NULL,
  6129. pMetaSpriteOld->hwnd);
  6130. if (pSprite)
  6131. {
  6132. PDEVOBJ poBestHdev(hdevBest);
  6133. SPRITELOCK slockBest(poBestHdev);
  6134. POINTL ptlDst;
  6135. // copy sprite shape from best existing sprite.
  6136. vSpTransferShape(pSprite, pSpriteBest);
  6137. // The sprite position need to be adjusted based on
  6138. // poDevice origin. need to convert from hdevBest
  6139. // coordinate.
  6140. // poBestHdev coordinate to meta coordinate
  6141. ptlDst.x =
  6142. pSpriteBest->ptlDst.x + poBestHdev.pptlOrigin()->x;
  6143. ptlDst.y =
  6144. pSpriteBest->ptlDst.y + poBestHdev.pptlOrigin()->y;
  6145. // meta coordinate to poDevice coordinate
  6146. ptlDst.x -= poDevice.pptlOrigin()->x;
  6147. ptlDst.y -= poDevice.pptlOrigin()->y;
  6148. if (bSpUpdatePosition(pSprite, &ptlDst))
  6149. {
  6150. // Put the sprite into meta sprite.
  6151. pMetaSpriteNew->apSprite[i] = pSprite;
  6152. pSprite->pMetaSprite = pMetaSpriteNew;
  6153. }
  6154. else
  6155. {
  6156. vSpDeleteSprite(pSprite);
  6157. bError = TRUE;
  6158. }
  6159. }
  6160. else
  6161. {
  6162. bError = TRUE;
  6163. }
  6164. }
  6165. if (bError)
  6166. {
  6167. // if there is any error, stop looping, no more creation.
  6168. break;
  6169. }
  6170. }
  6171. if (!bError)
  6172. {
  6173. // Add this node to the head of the meta-sprite list:
  6174. pMetaSpriteNew->pNext = pStateNew->pListMeta;
  6175. pStateNew->pListMeta = pMetaSpriteNew;
  6176. }
  6177. }
  6178. }
  6179. // check any sprite left in old meta, if so delete them.
  6180. for (i = 0; i < pMetaSpriteOld->chSprite ; i++)
  6181. {
  6182. if (pMetaSpriteOld->apSprite[i] != NULL)
  6183. {
  6184. vSpDeleteSprite(pMetaSpriteOld->apSprite[i]);
  6185. }
  6186. }
  6187. // Remove old meta sprite from the linked list :
  6188. if (pStateOld->pListMeta == pMetaSpriteOld)
  6189. {
  6190. pStateOld->pListMeta = pMetaSpriteOld->pNext;
  6191. }
  6192. else
  6193. {
  6194. for (METASPRITE *pTmp = pStateOld->pListMeta;
  6195. pTmp->pNext != pMetaSpriteOld;
  6196. pTmp = pTmp->pNext)
  6197. ;
  6198. pTmp->pNext = pMetaSpriteOld->pNext;
  6199. }
  6200. if (bError)
  6201. {
  6202. // Delete new meta sprite.
  6203. for (i = 0; i < pMetaSpriteNew->chSprite ; i++)
  6204. {
  6205. if (pMetaSpriteNew->apSprite[i] != NULL)
  6206. {
  6207. vSpDeleteSprite(pMetaSpriteNew->apSprite[i]);
  6208. }
  6209. }
  6210. VFREEMEM(pMetaSpriteNew);
  6211. pMetaSpriteNew = NULL;
  6212. }
  6213. // Delete meta sprite.
  6214. VFREEMEM(pMetaSpriteOld);
  6215. return(pMetaSpriteNew);
  6216. }
  6217. /******************************Public*Routine******************************\
  6218. * VOID vSpDynamicModeChange
  6219. *
  6220. * This function transfers all layered-window sprites from one PDEV to the
  6221. * other.
  6222. *
  6223. * Note that it transfers only layered-window sprites. Sprites that don't
  6224. * have an associated hwnd are left with the old PDEV.
  6225. *
  6226. * 2-Jul-1998 -by- Hideyuki Nagase [hideyukn]
  6227. * DDML (meta) mode change support.
  6228. *
  6229. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  6230. * Wrote it.
  6231. \**************************************************************************/
  6232. VOID vSpDynamicModeChange(
  6233. HDEV hdevA,
  6234. HDEV hdevB)
  6235. {
  6236. SPRITESTATE StateTmp;
  6237. SPRITESTATE* pStateA;
  6238. SPRITESTATE* pStateB;
  6239. ULONG ulTmp;
  6240. SPRITE* pSprite;
  6241. SPRITE* pSpriteNext;
  6242. SPRITE* pSpriteNew;
  6243. METASPRITE* pMetaSprite;
  6244. METASPRITE* pMetaSpriteNew;
  6245. METASPRITE* pMetaSpriteNext;
  6246. UINT i, j;
  6247. PDEVOBJ poA(hdevA);
  6248. PDEVOBJ poB(hdevB);
  6249. // Sprite state, being 'below the DDI level', is device specific.
  6250. // As such, it is tranferred along with the rest of the device
  6251. // specific state on the dynamic mode change.
  6252. //
  6253. // Do that now:
  6254. pStateA = poA.pSpriteState();
  6255. pStateB = poB.pSpriteState();
  6256. StateTmp = *pStateA;
  6257. *pStateA = *pStateB;
  6258. *pStateB = StateTmp;
  6259. // Swap back the drag-rect width:
  6260. ulTmp = pStateA->ulDragDimension;
  6261. pStateA->ulDragDimension = pStateB->ulDragDimension;
  6262. pStateB->ulDragDimension = ulTmp;
  6263. // Now find any 'hdev' references and correct them:
  6264. vSpCorrectHdevReferences(pStateA, hdevA);
  6265. vSpCorrectHdevReferences(pStateB, hdevB);
  6266. // Now that we've transferred the state, grab the locks:
  6267. SPRITELOCK slockA(poA);
  6268. SPRITELOCK slockB(poB);
  6269. pSprite = pStateA->pBottomCursor;
  6270. while(pSprite != NULL)
  6271. {
  6272. SPRITE* pNextSprite = pSprite->pNextZ;
  6273. vSpDeleteSprite(pSprite);
  6274. pSprite = pNextSprite;
  6275. }
  6276. pStateA->pTopCursor = NULL;
  6277. pStateA->pBottomCursor = NULL;
  6278. pStateA->ulNumCursors = 0;
  6279. pSprite = pStateB->pBottomCursor;
  6280. while(pSprite != NULL)
  6281. {
  6282. SPRITE* pNextSprite = pSprite->pNextZ;
  6283. vSpDeleteSprite(pSprite);
  6284. pSprite = pNextSprite;
  6285. }
  6286. pStateB->pTopCursor = NULL;
  6287. pStateB->pBottomCursor = NULL;
  6288. pStateB->ulNumCursors = 0;
  6289. // But the sprites themselves logically stay with the old PDEV
  6290. // and shouldn't be transferred in the first place. So
  6291. // now that we've transferred the broad state, we have to go
  6292. // back through and individually transfer every sprites back
  6293. // to their original PDEV, accounting for the new display
  6294. // format at the same time.
  6295. if (poA.bMetaDriver() && poB.bMetaDriver())
  6296. {
  6297. // Exchange all Meta sprites between meta PDEVs.
  6298. pMetaSprite = pStateA->pListMeta;
  6299. while (pMetaSprite != NULL)
  6300. {
  6301. // Grab the 'next' pointer while we can, because we're about
  6302. // to delete 'pMetaSprite'!
  6303. pMetaSpriteNext = pMetaSprite->pNext;
  6304. pMetaSpriteNew = pSpTransferMetaSprite(hdevB, hdevA, pMetaSprite);
  6305. if (pMetaSpriteNew != NULL)
  6306. {
  6307. // Mark the new sprites in 'B's list as being just
  6308. // of transferring:
  6309. pMetaSpriteNew->fl |= SPRITE_FLAG_JUST_TRANSFERRED;
  6310. }
  6311. pMetaSprite = pMetaSpriteNext;
  6312. }
  6313. // Transfer all the sprites that now live in 'B' back to 'A',
  6314. // skipping the ones we just transferred:
  6315. pMetaSprite = pStateB->pListMeta;
  6316. while (pMetaSprite != NULL)
  6317. {
  6318. // Grab the 'next' pointer while we can, because we're about
  6319. // to delete 'pMetaSprite'!
  6320. pMetaSpriteNext = pMetaSprite->pNext;
  6321. // The 'just-transferred' flag is so that we don't transfer
  6322. // back to A sprites we just transferred to B:
  6323. if (!(pMetaSprite->fl & SPRITE_FLAG_JUST_TRANSFERRED))
  6324. {
  6325. pMetaSpriteNew = pSpTransferMetaSprite(hdevA, hdevB, pMetaSprite);
  6326. }
  6327. else
  6328. {
  6329. pMetaSprite->fl &= ~SPRITE_FLAG_JUST_TRANSFERRED;
  6330. }
  6331. pMetaSprite = pMetaSpriteNext;
  6332. }
  6333. }
  6334. else if (!poA.bMetaDriver() && !poB.bMetaDriver())
  6335. {
  6336. pSprite = pStateA->pListZ;
  6337. while (pSprite != NULL)
  6338. {
  6339. // Grab the 'next' pointer while we can, because we're about
  6340. // to delete 'pSprite'!
  6341. pSpriteNext = pSprite->pNextZ;
  6342. pSpriteNew = pSpTransferSprite(hdevB, pSprite);
  6343. if (pSpriteNew != NULL)
  6344. {
  6345. // Mark the new sprites in 'B's list as being just
  6346. // of transferring:
  6347. pSpriteNew->fl |= SPRITE_FLAG_JUST_TRANSFERRED;
  6348. }
  6349. pSprite = pSpriteNext;
  6350. }
  6351. // Transfer all the sprites that now live in 'B' back to 'A',
  6352. // skipping the ones we just transferred:
  6353. pSprite = pStateB->pListZ;
  6354. while (pSprite != NULL)
  6355. {
  6356. // Grab the 'next' pointer while we can, because we're about
  6357. // to delete 'pSprite'!
  6358. pSpriteNext = pSprite->pNextZ;
  6359. // The 'just-transferred' flag is so that we don't transfer
  6360. // back to A sprites we just transferred to B:
  6361. if (!(pSprite->fl & SPRITE_FLAG_JUST_TRANSFERRED))
  6362. {
  6363. pSpriteNew = pSpTransferSprite(hdevA, pSprite);
  6364. }
  6365. else
  6366. {
  6367. pSprite->fl &= ~SPRITE_FLAG_JUST_TRANSFERRED;
  6368. }
  6369. pSprite = pSpriteNext;
  6370. }
  6371. }
  6372. else
  6373. {
  6374. PDEVOBJ poMeta(poA.bMetaDriver() ? hdevA : hdevB);
  6375. PDEVOBJ poDev(poA.bMetaDriver() ? hdevB : hdevA);
  6376. SPRITESTATE* pStateMeta = poMeta.pSpriteState();
  6377. SPRITESTATE* pStateDev = poDev.pSpriteState();
  6378. BOOL bModeChgBtwnChildAndParent = FALSE;
  6379. for (ULONG iIndex = 0; iIndex < pStateMeta->cMultiMon; iIndex++)
  6380. {
  6381. // Find poMeta.hdev() (= originally this hdev *WAS* child device)
  6382. if (pStateMeta->ahdevMultiMon[iIndex] == poMeta.hdev())
  6383. {
  6384. bModeChgBtwnChildAndParent = TRUE;
  6385. // Put a device PDEV.
  6386. pStateMeta->ahdevMultiMon[iIndex] = poDev.hdev();
  6387. break;
  6388. }
  6389. }
  6390. if (bModeChgBtwnChildAndParent)
  6391. {
  6392. // This must be only happened when 2 to 1 mode change occured.
  6393. ASSERTGDI(poA.hdev() == poDev.hdev(),"hdevA must be device PDEV");
  6394. ASSERTGDI(poB.hdev() == poMeta.hdev(),"hdevB must be meta PDEV");
  6395. // Only scan meta sprite to delete meta sprite and delete it's
  6396. // child sprites which we will not use anymore.
  6397. pMetaSprite = pStateMeta->pListMeta;
  6398. while (pMetaSprite != NULL)
  6399. {
  6400. // Grab the 'next' pointer while we can, because we're about
  6401. // to delete 'pMetaSprite'!
  6402. pMetaSpriteNext = pMetaSprite->pNext;
  6403. // Get sprite from MetaSprite.
  6404. pSpMoveSpriteFromMeta(poDev.hdev(), poMeta.hdev(),
  6405. pMetaSprite, iIndex);
  6406. pMetaSprite = pMetaSpriteNext;
  6407. }
  6408. }
  6409. else
  6410. {
  6411. // First, convert sprites in poDev to meta sprites into poMeta
  6412. pSprite = pStateDev->pListZ;
  6413. while (pSprite != NULL)
  6414. {
  6415. // Grab the 'next' pointer while we can, because we're about
  6416. // to delete 'pSprite'!
  6417. pSpriteNext = pSprite->pNextZ;
  6418. // Convert to meta sprite. "pSprite" in parameter, will be
  6419. // deleted inside pSpConvertSpriteToMeta().
  6420. pMetaSpriteNew = pSpConvertSpriteToMeta(poMeta.hdev(),
  6421. poDev.hdev(),
  6422. pSprite);
  6423. if (pMetaSpriteNew != NULL)
  6424. {
  6425. // Mark the new sprites in 'B's list as being just
  6426. // of transferring:
  6427. pMetaSpriteNew->fl |= SPRITE_FLAG_JUST_TRANSFERRED;
  6428. }
  6429. pSprite = pSpriteNext;
  6430. }
  6431. // Second, convert sprites in poMeta to regular sprites into poDev.
  6432. pMetaSprite = pStateMeta->pListMeta;
  6433. while (pMetaSprite != NULL)
  6434. {
  6435. // Grab the 'next' pointer while we can, because we're about
  6436. // to delete 'pMetaSprite'!
  6437. pMetaSpriteNext = pMetaSprite->pNext;
  6438. // The 'just-transferred' flag is so that we don't convert
  6439. // back to regular sprites we just converted to meta.
  6440. if (!(pMetaSprite->fl & SPRITE_FLAG_JUST_TRANSFERRED))
  6441. {
  6442. // Convert from meta sprite. "pMetaSprite" in parameter, will
  6443. // be deleted inside pSpConvertSpriteFromMeta().
  6444. pSpriteNew = pSpConvertSpriteFromMeta(poDev.hdev(),
  6445. poMeta.hdev(),
  6446. pMetaSprite);
  6447. }
  6448. else
  6449. {
  6450. pMetaSprite->fl &= ~SPRITE_FLAG_JUST_TRANSFERRED;
  6451. }
  6452. pMetaSprite = pMetaSpriteNext;
  6453. }
  6454. }
  6455. }
  6456. }
  6457. /***************************************************************************\
  6458. * pSpGetSprite
  6459. *
  6460. * Returns the pointer to the associated sprite, given either a sprite
  6461. * handle or a window handle.
  6462. *
  6463. * 8-Oct-1997 -by- Vadim Gorokhovsky [vadimg]
  6464. * Wrote it.
  6465. \***************************************************************************/
  6466. SPRITE* pSpGetSprite(
  6467. SPRITESTATE* pState,
  6468. HWND hwnd,
  6469. HANDLE hSprite = NULL)
  6470. {
  6471. SPRITE* pSprite;
  6472. pSprite = (SPRITE*) hSprite;
  6473. if ((pSprite == NULL) && (hwnd != NULL))
  6474. {
  6475. for (pSprite = pState->pListZ;
  6476. pSprite != NULL;
  6477. pSprite = pSprite->pNextZ)
  6478. {
  6479. if (pSprite->hwnd == hwnd)
  6480. break;
  6481. }
  6482. }
  6483. return(pSprite);
  6484. }
  6485. /***************************************************************************\
  6486. * pSpGetMetaSprite
  6487. *
  6488. * Returns the pointer to the associated meta-sprite, given either a
  6489. * meta-sprite handle or a window handle.
  6490. *
  6491. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  6492. * Wrote it.
  6493. \***************************************************************************/
  6494. METASPRITE* pSpGetMetaSprite(
  6495. SPRITESTATE* pState,
  6496. HWND hwnd,
  6497. HANDLE hSprite = NULL)
  6498. {
  6499. METASPRITE* pMetaSprite;
  6500. ASSERTGDI((hwnd != NULL) || (hSprite != NULL),
  6501. "Expected a non-NULL handle");
  6502. pMetaSprite = (METASPRITE*) hSprite;
  6503. if ((pMetaSprite == NULL) && (hwnd != NULL))
  6504. {
  6505. for (pMetaSprite = pState->pListMeta;
  6506. pMetaSprite != NULL;
  6507. pMetaSprite = pMetaSprite->pNext)
  6508. {
  6509. if (pMetaSprite->hwnd == hwnd)
  6510. break;
  6511. }
  6512. }
  6513. return(pMetaSprite);
  6514. }
  6515. /***************************************************************************\
  6516. * VOID vSpZorderSprite
  6517. *
  6518. * Re-arranges the sprite z-order, which goes from bottom-most to top-most.
  6519. *
  6520. * 8-Oct-1997 -by- Vadim Gorokhovsky [vadimg]
  6521. * Wrote it.
  6522. \***************************************************************************/
  6523. VOID vSpZorderSprite(
  6524. HDEV hdev,
  6525. SPRITE* pSprite, // May be NULL
  6526. SPRITE* pSpriteInsertAfter) // May be NULL to make sprite bottom-most
  6527. {
  6528. SPRITESTATE* pState;
  6529. SPRITE* pTmp;
  6530. PDEVOBJ po(hdev);
  6531. pState = po.pSpriteState();
  6532. DEVLOCKOBJ dlo(po);
  6533. SPRITELOCK slock(po);
  6534. pTmp = pState->pListZ;
  6535. if ((pSprite == NULL) || (pTmp == NULL))
  6536. {
  6537. return;
  6538. }
  6539. // First, unlink pSprite from the list. Setting pSprite->pNextZ
  6540. // to NULL is mostly for debug purposes.
  6541. if (pTmp == pSprite)
  6542. {
  6543. pState->pListZ = pTmp->pNextZ;
  6544. pTmp->pNextZ = NULL;
  6545. }
  6546. else
  6547. {
  6548. SPRITE* pSpritePrev;
  6549. do {
  6550. if (pTmp == pSprite)
  6551. {
  6552. pSpritePrev->pNextZ = pTmp->pNextZ;
  6553. pTmp->pNextZ = NULL;
  6554. break;
  6555. }
  6556. pSpritePrev = pTmp;
  6557. pTmp = pTmp->pNextZ;
  6558. } while (pTmp != NULL);
  6559. }
  6560. // This would be bad, we probably didn't find it in the list:
  6561. if (pSprite->pNextZ != NULL)
  6562. {
  6563. WARNING("vSpZorderSprite: sprite not unlinked!");
  6564. return;
  6565. }
  6566. if (pSpriteInsertAfter == NULL)
  6567. {
  6568. // Insert pSprite as the bottom-most one, i.e. first in the list:
  6569. pSprite->pNextZ = pState->pListZ;
  6570. pState->pListZ = pSprite;
  6571. }
  6572. else
  6573. {
  6574. pSprite->pNextZ = pSpriteInsertAfter->pNextZ;
  6575. pSpriteInsertAfter->pNextZ = pSprite;
  6576. }
  6577. vSpRenumberZOrder(pState);
  6578. pState->bValidRange = FALSE;
  6579. vSpRedrawSprite(pSprite);
  6580. }
  6581. /***************************************************************************\
  6582. * BOOL bSpPtInSprite
  6583. *
  6584. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  6585. * Wrote it.
  6586. \***************************************************************************/
  6587. BOOL bSpPtInSprite(
  6588. SPRITE* pSprite,
  6589. int x,
  6590. int y)
  6591. {
  6592. BOOL bRet = FALSE; // Assume failure
  6593. SPRITESTATE* pState;
  6594. SURFOBJ* psoHitTest;
  6595. POINTL OffHitTest;
  6596. RECTL rclPoint;
  6597. ULONG* pulPixel;
  6598. FLONG flModeMasks;
  6599. if (!pSprite)
  6600. {
  6601. return FALSE;
  6602. }
  6603. pState = pSprite->pState;
  6604. PDEVOBJ po(pState->hdev);
  6605. DEVLOCKOBJ dlo(po); // Needed to access 'pState'
  6606. SPRITELOCK slock(po);
  6607. psoHitTest = pState->psoHitTest;
  6608. rclPoint.left = x;
  6609. rclPoint.top = y;
  6610. rclPoint.right = x + 1;
  6611. rclPoint.bottom = y + 1;
  6612. // Compute the mode masks. Hit surface has same format as the screen.
  6613. XEPALOBJ palHitTest(
  6614. SURFOBJ_TO_SURFACE_NOT_NULL(pSprite->pState->psoScreen)->ppal());
  6615. if (palHitTest.bIsBitfields())
  6616. {
  6617. // Bug 280033: Make sure we only check to see if bits contained in
  6618. // one of bitfields below have been modified. If we don't do this,
  6619. // then we would get the wrong answer in some cases, such as 16bpp
  6620. // at 5-5-5 where the alphablend code would zero out the 16th bit,
  6621. // which doesn't mean that the sprite is visible because the value
  6622. // of that bit is undefined in this particular color resolution.
  6623. flModeMasks = palHitTest.flRed() |
  6624. palHitTest.flGre() |
  6625. palHitTest.flBlu();
  6626. }
  6627. else
  6628. {
  6629. // Doesn't matter what we put here because bits that don't belong to
  6630. // the color won't be modified by the alphablend code.
  6631. flModeMasks = 0xffffffff;
  6632. }
  6633. // First, see if the point intersects the sprite's bounds.
  6634. // If not, we're done.
  6635. if (bIntersect(&pSprite->rclSprite, &rclPoint))
  6636. {
  6637. OffHitTest.x = -x;
  6638. OffHitTest.y = -y;
  6639. pulPixel = (ULONG*) psoHitTest->pvScan0;
  6640. ASSERTGDI(psoHitTest->iType == STYPE_BITMAP,
  6641. "Hit-test surface must be STYPE_BITMAP!");
  6642. // Okay, now let's narrow it down. To deal with
  6643. // alpha, transparency, and funky transforms, we
  6644. // accomplish the hit testing by setting a pixel to
  6645. // a specific value, asking the sprite to redraw that
  6646. // pixel, and then checking to see if the value
  6647. // changed.
  6648. //
  6649. // We actually don't have to do this for rectangular,
  6650. // non-rotated opaque sprites...
  6651. *pulPixel = 0L;
  6652. vSpComposite(pSprite, &OffHitTest, psoHitTest, &rclPoint);
  6653. if (((*pulPixel) & flModeMasks) != 0)
  6654. {
  6655. bRet = TRUE;
  6656. }
  6657. else
  6658. {
  6659. // Unfortunately, the sprite may have chosen to draw in
  6660. // the colour that we used to do the check. So to make
  6661. // sure, try again using a different colour:
  6662. *pulPixel = ~0L;
  6663. vSpComposite(pSprite, &OffHitTest, psoHitTest, &rclPoint);
  6664. bRet = (((*pulPixel) & flModeMasks) != flModeMasks);
  6665. }
  6666. }
  6667. return(bRet);
  6668. }
  6669. /***************************************************************************\
  6670. * VOID vSpUpdateSpriteVisRgn
  6671. *
  6672. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  6673. * Wrote it.
  6674. \***************************************************************************/
  6675. VOID vSpUpdateSpriteVisRgn(
  6676. HDEV hdev)
  6677. {
  6678. SPRITESTATE* pState;
  6679. SPRITE* pSprite;
  6680. POINTL Offset;
  6681. BOOL bMore;
  6682. BOOL bEqual;
  6683. REGION* prgnOld;
  6684. REGION* prgnNew;
  6685. CLIPENUMRECT ClipOld;
  6686. CLIPENUMRECT ClipNew;
  6687. BOOL bOldMore;
  6688. BOOL bNewMore;
  6689. ULONG i;
  6690. PDEVOBJ po(hdev);
  6691. pState = po.pSpriteState();
  6692. pSprite = pState->pListZ;
  6693. if (pSprite == NULL)
  6694. return;
  6695. for (pSprite = pState->pListZ;
  6696. pSprite != NULL;
  6697. pSprite = pSprite->pNextZ)
  6698. {
  6699. if (pSprite->hwnd != NULL)
  6700. {
  6701. UserVisrgnFromHwnd(&pState->hrgn, pSprite->hwnd);
  6702. RGNMEMOBJ rmoNew;
  6703. RGNOBJAPI roClip(pState->hrgn, FALSE);
  6704. if (!roClip.bValid() || !rmoNew.bValid() || !rmoNew.bCopy(roClip))
  6705. {
  6706. rmoNew.vDeleteRGNOBJ();
  6707. }
  6708. else
  6709. {
  6710. // Adjust for this device's multi-mon offset:
  6711. Offset.x = -po.pptlOrigin()->x;
  6712. Offset.y = -po.pptlOrigin()->y;
  6713. rmoNew.bOffset(&Offset);
  6714. // Assume that the two regions will be equal:
  6715. bEqual = TRUE;
  6716. // Now check to see if the two clip regions really are equal:
  6717. prgnNew = rmoNew.prgnGet();
  6718. prgnOld = pSprite->prgnClip;
  6719. if (prgnOld == NULL)
  6720. {
  6721. // There was no old region. Let's assume the new one
  6722. // doesn't have trivial clipping:
  6723. bEqual = FALSE;
  6724. }
  6725. else
  6726. {
  6727. ECLIPOBJ ecoOld;
  6728. ECLIPOBJ ecoNew;
  6729. ERECTL erclUnclipped;
  6730. // If the sprite was not visible due to clipping,
  6731. // bSpUpdatePosition leaves 'rclSprite' as empty.
  6732. // Consequently, we can't use 'rclSprite' to determine
  6733. // the clip object complexity. Re-derive the
  6734. // unclipped sprite bounds:
  6735. erclUnclipped.left = pSprite->ptlDst.x;
  6736. erclUnclipped.top = pSprite->ptlDst.y;
  6737. erclUnclipped.right = erclUnclipped.left
  6738. + (pSprite->rclSrc.right - pSprite->rclSrc.left);
  6739. erclUnclipped.bottom = erclUnclipped.top
  6740. + (pSprite->rclSrc.bottom - pSprite->rclSrc.top);
  6741. ecoOld.vSetup(prgnOld, erclUnclipped);
  6742. ecoNew.vSetup(prgnNew, erclUnclipped);
  6743. if (ecoOld.erclExclude().bEmpty() ^
  6744. ecoNew.erclExclude().bEmpty())
  6745. {
  6746. // One or the other (but not both) are empty, so are
  6747. // unequal:
  6748. bEqual = FALSE;
  6749. }
  6750. else if ((ecoOld.iDComplexity == DC_TRIVIAL) &&
  6751. (ecoNew.iDComplexity == DC_TRIVIAL))
  6752. {
  6753. // Both are trivially clipped, so are equal.
  6754. }
  6755. else if (ecoOld.iDComplexity != ecoNew.iDComplexity)
  6756. {
  6757. // The clipping complexity is different, so the regions are
  6758. // unequal:
  6759. bEqual = FALSE;
  6760. }
  6761. else
  6762. {
  6763. // Okay, we've got work to do. We want to see if the
  6764. // regions are any different where it intersects with the
  6765. // sprite. We do this by constructing and enumerating
  6766. // corresponding clip objects:
  6767. ecoOld.cEnumStart(FALSE, CT_RECTANGLES, CD_ANY, 100);
  6768. ecoNew.cEnumStart(FALSE, CT_RECTANGLES, CD_ANY, 100);
  6769. bOldMore = TRUE;
  6770. bNewMore = TRUE;
  6771. do {
  6772. ClipOld.c = 0;
  6773. ClipNew.c = 0;
  6774. if (bOldMore)
  6775. bOldMore = ecoOld.bEnum(sizeof(ClipOld), &ClipOld);
  6776. if (bNewMore)
  6777. bNewMore = ecoNew.bEnum(sizeof(ClipNew), &ClipNew);
  6778. if (ClipOld.c != ClipNew.c)
  6779. {
  6780. bEqual = FALSE;
  6781. break;
  6782. }
  6783. for (i = 0; i < ClipOld.c; i++)
  6784. {
  6785. if ((ClipNew.arcl[i].left
  6786. != ClipOld.arcl[i].left) ||
  6787. (ClipNew.arcl[i].top
  6788. != ClipOld.arcl[i].top) ||
  6789. (ClipNew.arcl[i].right
  6790. != ClipOld.arcl[i].right) ||
  6791. (ClipNew.arcl[i].bottom
  6792. != ClipOld.arcl[i].bottom))
  6793. {
  6794. bEqual = FALSE;
  6795. bOldMore = FALSE;
  6796. bNewMore = FALSE;
  6797. break;
  6798. }
  6799. }
  6800. } while (bOldMore || bNewMore);
  6801. }
  6802. }
  6803. // Free the old region (if any) and set the new one:
  6804. vSpFreeClipResources(pSprite);
  6805. pSprite->prgnClip = prgnNew;
  6806. pSprite->prgnClip->vStamp();
  6807. // Grab some locks we need for drawing.
  6808. PDEVOBJ po(pState->hdev);
  6809. DEVLOCKOBJ dlo(po);
  6810. SPRITELOCK slock(po);
  6811. // We detect the case when the sprite has an empty VisRgn
  6812. // primarily for DirectDraw, so that we can unhook sprites
  6813. // and get out of its way when it goes full-screen.
  6814. //
  6815. // Note that we have to do this obscured check even if 'bEqual'
  6816. // is true because 'bEqual' applies only to the intersection
  6817. // with the current sprite rectangle, and the obscuring flag is
  6818. // independent of the sprite size or location.
  6819. pSprite->fl &= ~SPRITE_FLAG_CLIPPING_OBSCURED;
  6820. if (rmoNew.bInside(&pState->rclScreen) != REGION_RECT_INTERSECT)
  6821. pSprite->fl |= SPRITE_FLAG_CLIPPING_OBSCURED;
  6822. bSpUpdatePosition(pSprite, &pSprite->ptlDst);
  6823. if (gpto != NULL)
  6824. {
  6825. vSpCheckForWndobjOverlap(pState,
  6826. &pSprite->rclSprite,
  6827. &pSprite->rclSprite);
  6828. }
  6829. // Only if the regions, intersected with the sprite, are unequal
  6830. // do we do the repaint. We do this because we get called
  6831. // constantly when any window is moving, even if none of the
  6832. // movement intersects with the sprite.
  6833. if (!bEqual)
  6834. {
  6835. // Note that we could go further and just redraw the
  6836. // difference in the regions. At this point, I can't
  6837. // be bothered. We'll redraw the whole thing.
  6838. vSpRedrawSprite(pSprite);
  6839. }
  6840. }
  6841. }
  6842. }
  6843. }
  6844. /////////////////////////////////////////////////////////////////////////////
  6845. // Window Manager callable functions
  6846. /////////////////////////////////////////////////////////////////////////////
  6847. /***************************************************************************\
  6848. * BOOL GreCreateSprite
  6849. *
  6850. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  6851. * Wrote it.
  6852. \***************************************************************************/
  6853. HANDLE GreCreateSprite(
  6854. HDEV hdev,
  6855. HWND hwnd,
  6856. RECT* prc)
  6857. {
  6858. SPRITESTATE* pState;
  6859. METASPRITE* pMetaSprite;
  6860. SPRITE* pSprite;
  6861. ULONG cjAlloc;
  6862. ULONG i;
  6863. HANDLE pRet = NULL;
  6864. PDEVOBJ po(hdev);
  6865. pState = po.pSpriteState();
  6866. // When running multi-mon, handle the creation of the meta sprite:
  6867. if (pState->cMultiMon)
  6868. {
  6869. cjAlloc = sizeof(METASPRITE)
  6870. + pState->cMultiMon * sizeof(pMetaSprite->apSprite[0]);
  6871. pMetaSprite = (METASPRITE*) PALLOCNOZ(cjAlloc, 'mpsG');
  6872. if (pMetaSprite)
  6873. {
  6874. for (i = 0; i < pState->cMultiMon; i++)
  6875. {
  6876. PDEVOBJ poMon(pState->ahdevMultiMon[i]);
  6877. POINTL *pptlDstInit = NULL;
  6878. POINTL ptlDstInit;
  6879. if (prc)
  6880. {
  6881. ptlDstInit.x = prc->left - poMon.pptlOrigin()->x;
  6882. ptlDstInit.y = prc->top - poMon.pptlOrigin()->y;
  6883. pptlDstInit = &ptlDstInit;
  6884. }
  6885. pSprite = pSpCreateSprite(pState->ahdevMultiMon[i],
  6886. (RECTL*) prc,
  6887. hwnd,
  6888. pptlDstInit);
  6889. if (pSprite == NULL)
  6890. {
  6891. for (; i > 0; i--)
  6892. {
  6893. vSpDeleteSprite(pMetaSprite->apSprite[i - 1]);
  6894. }
  6895. VFREEMEM(pMetaSprite);
  6896. return(pRet);
  6897. }
  6898. pMetaSprite->apSprite[i] = pSprite;
  6899. pSprite->pMetaSprite = pMetaSprite;
  6900. }
  6901. pMetaSprite->hwnd = hwnd;
  6902. pMetaSprite->chSprite = pState->cMultiMon;
  6903. pMetaSprite->fl = 0;
  6904. // Add this node to the head of the meta-sprite list:
  6905. pMetaSprite->pNext = pState->pListMeta;
  6906. pState->pListMeta = pMetaSprite;
  6907. pRet = pMetaSprite;
  6908. }
  6909. }
  6910. else
  6911. {
  6912. // Note that USER doesn't actually need the pointer to the sprite
  6913. // since it uses pSpGetSprite to reference the sprite.
  6914. pRet = pSpCreateSprite(hdev, (RECTL*) prc, hwnd);
  6915. }
  6916. return(pRet);
  6917. }
  6918. /***************************************************************************\
  6919. * BOOL GreDeleteSprite
  6920. *
  6921. * 8-Oct-1997 -by- Vadim Gorokhovsky [vadimg]
  6922. * Wrote it.
  6923. \***************************************************************************/
  6924. BOOL GreDeleteSprite(
  6925. HDEV hdev,
  6926. HWND hwnd,
  6927. HANDLE hSprite)
  6928. {
  6929. SPRITESTATE* pState;
  6930. METASPRITE* pMetaSprite;
  6931. METASPRITE* pTmp;
  6932. SPRITE* pSprite;
  6933. ULONG i;
  6934. BOOL bRet = FALSE;
  6935. PDEVOBJ po(hdev);
  6936. pState = po.pSpriteState();
  6937. if (pState->cMultiMon)
  6938. {
  6939. pMetaSprite = pSpGetMetaSprite(pState, hwnd, hSprite);
  6940. if (pMetaSprite)
  6941. {
  6942. for (i = 0; i < pState->cMultiMon; i++)
  6943. {
  6944. vSpDeleteSprite(pMetaSprite->apSprite[i]);
  6945. }
  6946. // Remove this sprite from the linked list:
  6947. if (pState->pListMeta == pMetaSprite)
  6948. {
  6949. pState->pListMeta = pMetaSprite->pNext;
  6950. }
  6951. else
  6952. {
  6953. for (pTmp = pState->pListMeta;
  6954. pTmp->pNext != pMetaSprite;
  6955. pTmp = pTmp->pNext)
  6956. ;
  6957. pTmp->pNext = pMetaSprite->pNext;
  6958. }
  6959. VFREEMEM(pMetaSprite);
  6960. bRet = TRUE;
  6961. }
  6962. }
  6963. else
  6964. {
  6965. pSprite = pSpGetSprite(pState, hwnd, hSprite);
  6966. if (pSprite)
  6967. {
  6968. vSpDeleteSprite(pSprite);
  6969. bRet = TRUE;
  6970. }
  6971. }
  6972. return(bRet);
  6973. }
  6974. /***************************************************************************\
  6975. * BOOL GreGetSpriteAttributes
  6976. *
  6977. * 14-Mar-2000 -by- Jeff Stall [jstall]
  6978. * Wrote it.
  6979. \***************************************************************************/
  6980. BOOL GreGetSpriteAttributes(
  6981. HDEV hdev,
  6982. HWND hwnd,
  6983. HANDLE hSprite,
  6984. COLORREF* lpcrKey,
  6985. BLENDFUNCTION* pblend,
  6986. DWORD* pdwFlags)
  6987. {
  6988. SPRITESTATE* pState;
  6989. SPRITE* pSprite = NULL;
  6990. BOOL bRet = FALSE;
  6991. PDEVOBJ po(hdev);
  6992. ASSERTGDI(lpcrKey != NULL, "Ensure valid pointer");
  6993. ASSERTGDI(pblend != NULL, "Ensure valid pointer");
  6994. ASSERTGDI(pdwFlags != NULL, "Ensure valid pointer");
  6995. //
  6996. // Get the sprite object.
  6997. //
  6998. pState = po.pSpriteState();
  6999. if (pState->cMultiMon)
  7000. {
  7001. //
  7002. // On a multimon system, query the values from the first sprite.
  7003. //
  7004. METASPRITE * pMetaSprite = pSpGetMetaSprite(pState, hwnd, hSprite);
  7005. if (pMetaSprite != NULL)
  7006. {
  7007. pSprite = pMetaSprite->apSprite[0];
  7008. ASSERTGDI(pSprite != NULL, "Sprite should exist");
  7009. }
  7010. }
  7011. else
  7012. {
  7013. pSprite = pSpGetSprite(pState, hwnd, hSprite);
  7014. }
  7015. //
  7016. // Query the data from the sprite.
  7017. //
  7018. if (pSprite != NULL)
  7019. {
  7020. bRet = TRUE;
  7021. *lpcrKey = pSprite->cachedAttributes.crKey;
  7022. *pblend = pSprite->cachedAttributes.bf;
  7023. *pdwFlags = pSprite->cachedAttributes.dwShape;
  7024. }
  7025. return(bRet);
  7026. }
  7027. /***************************************************************************\
  7028. * BOOL GreUpdateSprite
  7029. *
  7030. * 8-Oct-1997 -by- Vadim Gorokhovsky [vadimg]
  7031. * Wrote it.
  7032. \***************************************************************************/
  7033. BOOL GreUpdateSprite(
  7034. HDEV hdev,
  7035. HWND hwnd,
  7036. HANDLE hSprite,
  7037. HDC hdcDst,
  7038. POINT* pptDst,
  7039. SIZE* psize,
  7040. HDC hdcSrc,
  7041. POINT* pptSrc,
  7042. COLORREF crKey,
  7043. BLENDFUNCTION* pblend,
  7044. DWORD dwShape,
  7045. RECT* prcDirty)
  7046. {
  7047. SPRITESTATE* pState;
  7048. METASPRITE* pMetaSprite;
  7049. SPRITE* pSprite;
  7050. ULONG i;
  7051. POINTL* pptlDstTmp;
  7052. POINTL ptlDstTmp;
  7053. BOOL bRet = FALSE;
  7054. ERECTL erclDirty;
  7055. if (prcDirty)
  7056. {
  7057. // Let's make sure we don't modify the caller memory pointed to by
  7058. // prcldirty
  7059. erclDirty = *((ERECTL *) prcDirty);
  7060. prcDirty = (RECT *) &erclDirty;
  7061. }
  7062. PDEVOBJ po(hdev);
  7063. if (po.bDisabled())
  7064. return bRet;
  7065. pState = po.pSpriteState();
  7066. if (pState->cMultiMon)
  7067. {
  7068. pMetaSprite = pSpGetMetaSprite(pState, hwnd, hSprite);
  7069. if (pMetaSprite)
  7070. {
  7071. bRet = TRUE; // This allows us to record single monitor
  7072. // failures by ANDing bRet with the return
  7073. // value from bSpUpdateSprite
  7074. for (i = 0; i < pState->cMultiMon; i++)
  7075. {
  7076. PDEVOBJ po(pState->ahdevMultiMon[i]);
  7077. pptlDstTmp = NULL;
  7078. if (pptDst != NULL)
  7079. {
  7080. ptlDstTmp.x = pptDst->x - po.pptlOrigin()->x;
  7081. ptlDstTmp.y = pptDst->y - po.pptlOrigin()->y;
  7082. pptlDstTmp = &ptlDstTmp;
  7083. }
  7084. bRet &= bSpUpdateSprite(pMetaSprite->apSprite[i],
  7085. hdcDst,
  7086. pptlDstTmp,
  7087. psize,
  7088. hdcSrc,
  7089. (POINTL*) pptSrc,
  7090. crKey,
  7091. pblend,
  7092. dwShape,
  7093. (RECTL*)prcDirty);
  7094. }
  7095. }
  7096. }
  7097. else
  7098. {
  7099. pSprite = pSpGetSprite(pState, hwnd, hSprite);
  7100. if (pSprite)
  7101. {
  7102. bRet = bSpUpdateSprite(pSprite,
  7103. hdcDst,
  7104. (POINTL*) pptDst,
  7105. psize,
  7106. hdcSrc,
  7107. (POINTL*) pptSrc,
  7108. crKey,
  7109. pblend,
  7110. dwShape,
  7111. (RECTL*) prcDirty);
  7112. }
  7113. }
  7114. return(bRet);
  7115. }
  7116. /***************************************************************************\
  7117. * BOOL GrePtInSprite
  7118. *
  7119. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  7120. * Wrote it.
  7121. \***************************************************************************/
  7122. BOOL APIENTRY GrePtInSprite(
  7123. HDEV hdev,
  7124. HWND hwnd,
  7125. int x,
  7126. int y)
  7127. {
  7128. SPRITESTATE* pState;
  7129. METASPRITE* pMetaSprite;
  7130. SPRITE* pSprite;
  7131. ULONG i;
  7132. BOOL bRet = FALSE;
  7133. PDEVOBJ po(hdev);
  7134. pState = po.pSpriteState();
  7135. if (pState->cMultiMon)
  7136. {
  7137. pMetaSprite = pSpGetMetaSprite(pState, hwnd);
  7138. if (pMetaSprite)
  7139. {
  7140. for (i = 0; i < pState->cMultiMon; i++)
  7141. {
  7142. PDEVOBJ po(pState->ahdevMultiMon[i]);
  7143. if (bSpPtInSprite(pMetaSprite->apSprite[i],
  7144. x - po.pptlOrigin()->x,
  7145. y - po.pptlOrigin()->y))
  7146. {
  7147. bRet = TRUE;
  7148. break;
  7149. }
  7150. }
  7151. }
  7152. }
  7153. else
  7154. {
  7155. pSprite = pSpGetSprite(pState, hwnd);
  7156. if (pSprite)
  7157. {
  7158. bRet = bSpPtInSprite(pSprite, x, y);
  7159. }
  7160. }
  7161. return(bRet);
  7162. }
  7163. /***************************************************************************\
  7164. * BOOL GreUpdateSpriteVisRgn
  7165. *
  7166. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  7167. * Wrote it.
  7168. \***************************************************************************/
  7169. VOID APIENTRY GreUpdateSpriteVisRgn(
  7170. HDEV hdev)
  7171. {
  7172. ULONG i;
  7173. SPRITESTATE* pState;
  7174. BOOL bRet = TRUE;
  7175. PDEVOBJ po(hdev);
  7176. pState = po.pSpriteState();
  7177. if (pState->cMultiMon)
  7178. {
  7179. for (i = 0; i < pState->cMultiMon; i++)
  7180. {
  7181. vSpUpdateSpriteVisRgn(pState->ahdevMultiMon[i]);
  7182. }
  7183. }
  7184. else
  7185. {
  7186. vSpUpdateSpriteVisRgn(pState->hdev);
  7187. }
  7188. }
  7189. /***************************************************************************\
  7190. * BOOL GreZorderSprite
  7191. *
  7192. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  7193. * Wrote it.
  7194. \***************************************************************************/
  7195. VOID APIENTRY GreZorderSprite(
  7196. HDEV hdev,
  7197. HWND hwnd,
  7198. HWND hwndInsertAfter)
  7199. {
  7200. SPRITESTATE* pState;
  7201. ULONG i;
  7202. PDEVOBJ po(hdev);
  7203. pState = po.pSpriteState();
  7204. if (pState->cMultiMon)
  7205. {
  7206. for (i = 0; i < pState->cMultiMon; i++)
  7207. {
  7208. HDEV hdevSingle = pState->ahdevMultiMon[i];
  7209. PDEVOBJ poSingle(hdevSingle);
  7210. SPRITESTATE *pSpriteStateSingle = poSingle.pSpriteState();
  7211. vSpZorderSprite(hdevSingle,
  7212. pSpGetSprite(pSpriteStateSingle, hwnd),
  7213. pSpGetSprite(pSpriteStateSingle, hwndInsertAfter));
  7214. }
  7215. }
  7216. else
  7217. {
  7218. vSpZorderSprite(pState->hdev,
  7219. pSpGetSprite(pState, hwnd),
  7220. pSpGetSprite(pState, hwndInsertAfter));
  7221. }
  7222. }
  7223. /////////////////////////////////////////////////////////////////////////////
  7224. // Software Cursors
  7225. /////////////////////////////////////////////////////////////////////////////
  7226. /******************************Public*Routine******************************\
  7227. * BOOL SpUpdateCursor
  7228. *
  7229. * Updates the shape for a cursor.
  7230. *
  7231. * Returns FALSE if the function fails, and sets both 'pSprite->psoMask'
  7232. * and 'pSprite->psoShape' to NULL.
  7233. *
  7234. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  7235. * Wrote it.
  7236. \**************************************************************************/
  7237. BOOL bSpUpdateCursor(
  7238. SPRITE* pSprite,
  7239. SURFOBJ* psoMono,
  7240. SURFOBJ* psoColor,
  7241. XLATEOBJ* pxlo,
  7242. RECTL* prclBounds) // Defines the parts of 'psoMono' and
  7243. // 'psoColor' to be used
  7244. {
  7245. BOOL bRet = FALSE; // Assume failure
  7246. SPRITESTATE* pState;
  7247. RECTL rclSrc;
  7248. SURFOBJ* psoMask;
  7249. DEVBITMAPINFO dbmi;
  7250. SURFMEM SurfDimo;
  7251. pState = pSprite->pState;
  7252. PDEVOBJ po(pState->hdev);
  7253. // Initialize some state for the sprite:
  7254. pSprite->rclSrc = *prclBounds;
  7255. if (psoMono == NULL)
  7256. {
  7257. // Handle the alpha cursor case:
  7258. ASSERTGDI((psoColor != NULL) && (psoColor->iBitmapFormat == BMF_32BPP),
  7259. "Expected BGRA surface");
  7260. ASSERTGDI((prclBounds->right <= (psoColor->sizlBitmap.cx)) &&
  7261. (prclBounds->bottom <= (psoColor->sizlBitmap.cy)),
  7262. "Bounds out of bounds");
  7263. // Mark this as an 'alpha' sprite:
  7264. pSprite->dwShape = ULW_ALPHA;
  7265. pSprite->BlendFunction.AlphaFormat = AC_SRC_ALPHA;
  7266. pSprite->BlendFunction.BlendOp = AC_SRC_OVER;
  7267. pSprite->BlendFunction.BlendFlags = 0;
  7268. pSprite->BlendFunction.SourceConstantAlpha = 0xff;
  7269. vSpCreateShape(pSprite,
  7270. &gptlZero,
  7271. psoColor,
  7272. NULL,
  7273. prclBounds,
  7274. gppalRGB,
  7275. BMF_32BPP,
  7276. TRUE); // Allocate from system memory because the
  7277. // Alpha Blending will most likely be done by
  7278. // the CPU, and it's expensive to transfer the
  7279. // cursor bitmap across the bus every time
  7280. bRet = (pSprite->psoShape != NULL);
  7281. }
  7282. else
  7283. {
  7284. // Handle the non-alpha cursor case:
  7285. ASSERTGDI((prclBounds->right <= (psoMono->sizlBitmap.cx)) &&
  7286. (prclBounds->bottom <= (psoMono->sizlBitmap.cy >> 1)),
  7287. "Bounds out of bounds");
  7288. psoMask = pSprite->psoMask;
  7289. if (psoMask != NULL)
  7290. {
  7291. // If the new mask is different sized than the old cached mask,
  7292. // free up the old cached mask:
  7293. if ((psoMask->sizlBitmap.cx != psoMono->sizlBitmap.cx) ||
  7294. (psoMask->sizlBitmap.cy != psoMono->sizlBitmap.cy))
  7295. {
  7296. bDeleteSurface(psoMask->hsurf);
  7297. psoMask = NULL;
  7298. }
  7299. }
  7300. // Create a surface to hold a copy of the mask:
  7301. if (psoMask == NULL)
  7302. {
  7303. dbmi.iFormat = BMF_1BPP;
  7304. dbmi.cxBitmap = psoMono->sizlBitmap.cx;
  7305. dbmi.cyBitmap = psoMono->sizlBitmap.cy;
  7306. dbmi.fl = BMF_TOPDOWN;
  7307. dbmi.hpal = NULL;
  7308. if (SurfDimo.bCreateDIB(&dbmi, NULL))
  7309. {
  7310. psoMask = SurfDimo.pSurfobj();
  7311. SurfDimo.vKeepIt();
  7312. SurfDimo.vSetPID(OBJECT_OWNER_PUBLIC);
  7313. }
  7314. }
  7315. // Copy the mask:
  7316. pSprite->psoMask = psoMask;
  7317. if (psoMask != NULL)
  7318. {
  7319. // Use the given bounds for the copy, adjusting 'bottom' so that
  7320. // we can copy both the 'AND' parts and the 'OR' parts in one blt:
  7321. rclSrc = *prclBounds;
  7322. rclSrc.bottom += (psoMask->sizlBitmap.cy >> 1);
  7323. EngCopyBits(psoMask, psoMono, NULL, NULL, &rclSrc, (POINTL*) &rclSrc);
  7324. }
  7325. // Now account for the color surface, if there is one:
  7326. if (psoColor == NULL)
  7327. {
  7328. vSpDeleteShape(pSprite);
  7329. bRet = TRUE;
  7330. }
  7331. else
  7332. {
  7333. vSpCreateShape(pSprite,
  7334. &gptlZero,
  7335. psoColor,
  7336. pxlo,
  7337. prclBounds,
  7338. po.ppalSurf(),
  7339. 0,
  7340. FALSE); // Allocate from video memory if
  7341. // possible, because the blit can be
  7342. // done entirely on the video card, and
  7343. // it's faster when the cursor bitmap is
  7344. // already there.
  7345. bRet = (pSprite->psoShape != NULL);
  7346. }
  7347. // Finally, mark this as a non-alpha 'cursor' sprite, and update some of
  7348. // the sprite fields that would normally be updated by vSpCreateShape:
  7349. pSprite->dwShape = ULW_CURSOR;
  7350. pSprite->flModeMasks = pState->flModeMasks;
  7351. pSprite->iModeFormat = pState->iModeFormat;
  7352. }
  7353. return(bRet);
  7354. }
  7355. /***************************************************************************\
  7356. * ULONG EngMovePointer
  7357. *
  7358. * Move the engine managed pointer on the device.
  7359. *
  7360. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  7361. * Wrote it.
  7362. \***************************************************************************/
  7363. VOID EngMovePointer(
  7364. SURFOBJ* pso,
  7365. LONG x,
  7366. LONG y,
  7367. RECTL* prcl) // Ignored
  7368. {
  7369. GDIFunctionID(EngMovePointer);
  7370. SPRITESTATE* pState;
  7371. SPRITE* pSprite;
  7372. POINTL ptlDst;
  7373. PDEVOBJ po(pso->hdev);
  7374. pState = po.pSpriteState();
  7375. if (pState->pTopCursor != NULL)
  7376. {
  7377. SPRITELOCK slock(po);
  7378. if(pState->pBottomCursor != pState->pTopCursor)
  7379. {
  7380. // rotate cursors if enough time has past
  7381. ULONG tickCount = NtGetTickCount();
  7382. ULONG elapsedTicks = tickCount - pState->ulTrailTimeStamp;
  7383. if(elapsedTicks >= pState->ulTrailPeriod)
  7384. {
  7385. // trial maintenance time ... either spawn off a new trail cursor
  7386. // or hide the oldest
  7387. // find the first trail cursor (cursor before top)
  7388. pSprite = pState->pBottomCursor;
  7389. while(pSprite->pNextZ != pState->pTopCursor) pSprite = pSprite->pNextZ;
  7390. // if it does not coincide with top cursor then spawn off another
  7391. if(pSprite->rclSprite.left != pState->pTopCursor->rclSprite.left ||
  7392. pSprite->rclSprite.top != pState->pTopCursor->rclSprite.top)
  7393. {
  7394. // hide the bottom most cursor
  7395. pSprite = pState->pBottomCursor;
  7396. bSpUpdatePosition(pSprite, NULL);
  7397. // rotate hidden cursor to front most
  7398. pState->pBottomCursor = pSprite->pNextZ;
  7399. // Reorder sprites
  7400. vSpZorderSprite(pso->hdev, pSprite, pState->pTopCursor);
  7401. pState->pTopCursor = pSprite;
  7402. }
  7403. else
  7404. {
  7405. // otherwise hide oldest visible trail
  7406. pSprite = pState->pBottomCursor;
  7407. while(pSprite != pState->pTopCursor)
  7408. {
  7409. if (pSprite->fl & SPRITE_FLAG_VISIBLE)
  7410. {
  7411. ASSERTGDI(pSprite->rclSprite.left != pSprite->rclSprite.right, "Invalid rclSprite for visible sprite.\n");
  7412. bSpUpdatePosition(pSprite, NULL);
  7413. break;
  7414. }
  7415. pSprite = pSprite->pNextZ;
  7416. }
  7417. }
  7418. // update time stamp
  7419. pState->ulTrailTimeStamp = tickCount;
  7420. }
  7421. }
  7422. if (x == -1)
  7423. {
  7424. // hide all cursors
  7425. ptlDst.x = LONG_MAX;
  7426. ptlDst.y = LONG_MAX;
  7427. pSprite = pState->pBottomCursor;
  7428. while(pSprite != NULL)
  7429. {
  7430. bSpUpdatePosition(pSprite, &ptlDst, FALSE);
  7431. pSprite = pSprite->pNextZ;
  7432. }
  7433. }
  7434. else
  7435. {
  7436. ptlDst.x = x - pState->xHotCursor;
  7437. ptlDst.y = y - pState->yHotCursor;
  7438. // update the position of the top most cursor
  7439. pSprite = pState->pTopCursor;
  7440. bSpUpdatePosition(pSprite, &ptlDst);
  7441. vSpRedrawSprite(pSprite);
  7442. }
  7443. // Nothing is more irritating than having a cursor that 'lags'. If
  7444. // the driver is a DDI batching driver (meaning that it updates the
  7445. // screen only occassionally unless we explicitly call DrvSynchronize),
  7446. // let's force it to update the screen now:
  7447. if (po.flGraphicsCaps2() & GCAPS2_SYNCTIMER)
  7448. {
  7449. po.vSync(po.pSurface()->pSurfobj(), NULL, DSS_TIMER_EVENT);
  7450. }
  7451. }
  7452. }
  7453. /***************************************************************************\
  7454. * ULONG EngSetPointerShape
  7455. *
  7456. * Sets the pointer shape for the GDI pointer simulations.
  7457. *
  7458. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  7459. * Wrote it.
  7460. \***************************************************************************/
  7461. ULONG EngSetPointerShape(
  7462. SURFOBJ* pso,
  7463. SURFOBJ* psoMask,
  7464. SURFOBJ* psoColor,
  7465. XLATEOBJ* pxlo,
  7466. LONG xHot,
  7467. LONG yHot,
  7468. LONG x,
  7469. LONG y,
  7470. RECTL* prclBounds,
  7471. FLONG fl)
  7472. {
  7473. HDEV hdev;
  7474. SPRITESTATE* pState;
  7475. SPRITE* pSprite;
  7476. ULONG ulRet = SPS_ACCEPT_NOEXCLUDE;
  7477. ULONG numCursors = ((fl & SPS_LENGTHMASK) >> 8) + 1;
  7478. ULONG ulFreq = (fl & SPS_FREQMASK) >> 12;
  7479. ULONG ulTrailPeriod = (ulFreq == 0 ? 0 : 1000 / ulFreq);
  7480. hdev = pso->hdev;
  7481. PDEVOBJ po(hdev);
  7482. pState = po.pSpriteState();
  7483. // Handle the hide case. We take the opportunity to delete the sprite,
  7484. // so that we can start out fresh the next time.
  7485. if ((psoMask == NULL) && (psoColor == NULL))
  7486. {
  7487. pSprite = pState->pBottomCursor;
  7488. while(pSprite != NULL)
  7489. {
  7490. SPRITE* pNextSprite = pSprite->pNextZ;
  7491. vSpDeleteSprite(pSprite);
  7492. pSprite = pNextSprite;
  7493. }
  7494. pState->pTopCursor = NULL;
  7495. pState->pBottomCursor = NULL;
  7496. pState->ulNumCursors = 0;
  7497. return(SPS_ACCEPT_NOEXCLUDE);
  7498. }
  7499. // adjust the number of cursors
  7500. while (pState->ulNumCursors < numCursors)
  7501. {
  7502. pSprite = pSpCreateSprite(hdev, NULL, 0);
  7503. if(pSprite == NULL)
  7504. break;
  7505. if(pState->pTopCursor == NULL)
  7506. {
  7507. pState->pTopCursor = pSprite;
  7508. }
  7509. pState->pBottomCursor = pSprite;
  7510. pState->ulNumCursors++;
  7511. }
  7512. while(pState->ulNumCursors > numCursors)
  7513. {
  7514. pSprite = pState->pBottomCursor;
  7515. pState->pBottomCursor = pSprite->pNextZ;
  7516. vSpDeleteSprite(pSprite);
  7517. pState->ulNumCursors--;
  7518. }
  7519. pState->ulTrailPeriod = ulTrailPeriod;
  7520. // Handle the show case.
  7521. if (pState->pTopCursor != NULL)
  7522. {
  7523. // hide and update the shape of all cursors
  7524. pSprite = pState->pBottomCursor;
  7525. // hide cursors
  7526. {
  7527. SPRITELOCK slock(po);
  7528. while(pSprite != NULL)
  7529. {
  7530. bSpUpdatePosition(pSprite, NULL, FALSE);
  7531. vSpRedrawSprite(pSprite);
  7532. pSprite = pSprite->pNextZ;
  7533. }
  7534. }
  7535. // update the shapes
  7536. pSprite = pState->pBottomCursor;
  7537. while(pSprite != NULL)
  7538. {
  7539. if (!bSpUpdateCursor(pSprite, psoMask, psoColor, pxlo, prclBounds))
  7540. {
  7541. ulRet = SPS_ERROR;
  7542. break;
  7543. }
  7544. pSprite = pSprite->pNextZ;
  7545. }
  7546. // Remember the hot spot and force EngMovePointer to redraw:
  7547. pState->xHotCursor = xHot - prclBounds->left;
  7548. pState->yHotCursor = yHot - prclBounds->top;
  7549. }
  7550. // Draw the cursor. Note that it's okay if 'pSpriteCursor' is NULL:
  7551. EngMovePointer(pso, x, y, NULL);
  7552. return(ulRet);
  7553. }
  7554. /******************************Public*Routine******************************\
  7555. * ULONG cIntersect
  7556. *
  7557. * This routine takes a list of rectangles from 'prclIn' and clips them
  7558. * in-place to the rectangle 'prclClip'. The input rectangles don't
  7559. * have to intersect 'prclClip'; the return value will reflect the
  7560. * number of input rectangles that did intersect, and the intersecting
  7561. * rectangles will be densely packed.
  7562. *
  7563. * History:
  7564. * 3-Apr-1996 -by- J. Andrew Goossen andrewgo
  7565. * Wrote it.
  7566. \**************************************************************************/
  7567. ULONG cIntersect(
  7568. RECTL* prclClip,
  7569. RECTL* prclIn, // List of rectangles
  7570. LONG c) // Can be zero
  7571. {
  7572. ULONG cIntersections;
  7573. RECTL* prclOut;
  7574. cIntersections = 0;
  7575. prclOut = prclIn;
  7576. for (; c != 0; prclIn++, c--)
  7577. {
  7578. prclOut->left = max(prclIn->left, prclClip->left);
  7579. prclOut->right = min(prclIn->right, prclClip->right);
  7580. if (prclOut->left < prclOut->right)
  7581. {
  7582. prclOut->top = max(prclIn->top, prclClip->top);
  7583. prclOut->bottom = min(prclIn->bottom, prclClip->bottom);
  7584. if (prclOut->top < prclOut->bottom)
  7585. {
  7586. prclOut++;
  7587. cIntersections++;
  7588. }
  7589. }
  7590. }
  7591. return(cIntersections);
  7592. }
  7593. /******************************Public*Routine******************************\
  7594. * BOOL bMoveDevDragRect
  7595. *
  7596. * Called by USER to move the drag rect on the screen.
  7597. *
  7598. * Note: Devlock must already have been acquired.
  7599. *
  7600. * History:
  7601. * 3-Apr-1996 -by- J. Andrew Goossen andrewgo
  7602. * Wrote it.
  7603. \**************************************************************************/
  7604. BOOL bMoveDevDragRect(
  7605. HDEV hdev, // Note that this may be a multi-mon meta-PDEV
  7606. RECTL *prclNew)
  7607. {
  7608. SPRITESTATE* pState;
  7609. ULONG ulDimension;
  7610. ULONG crclTemp;
  7611. ULONG i;
  7612. RECTL arclTemp[4];
  7613. SIZE siz;
  7614. PDEVOBJ po(hdev);
  7615. pState = po.pSpriteState();
  7616. po.vAssertDevLock();
  7617. ulDimension = pState->ulDragDimension;
  7618. arclTemp[0].left = prclNew->left;
  7619. arclTemp[0].right = prclNew->left + ulDimension;
  7620. arclTemp[0].top = prclNew->top;
  7621. arclTemp[0].bottom = prclNew->bottom;
  7622. arclTemp[1].left = prclNew->right - ulDimension;
  7623. arclTemp[1].right = prclNew->right;
  7624. arclTemp[1].top = prclNew->top;
  7625. arclTemp[1].bottom = prclNew->bottom;
  7626. arclTemp[2].left = prclNew->left + ulDimension;
  7627. arclTemp[2].right = prclNew->right - ulDimension;
  7628. arclTemp[2].top = prclNew->top;
  7629. arclTemp[2].bottom = prclNew->top + ulDimension;
  7630. arclTemp[3].left = prclNew->left + ulDimension;
  7631. arclTemp[3].right = prclNew->right - ulDimension;
  7632. arclTemp[3].top = prclNew->bottom - ulDimension;
  7633. arclTemp[3].bottom = prclNew->bottom;
  7634. // We have to clip to the specified rectangle in order to handle
  7635. // chip-window drag-rects for MDI applications.
  7636. crclTemp = cIntersect(&pState->rclDragClip, &arclTemp[0], 4);
  7637. for (i = 0; i < crclTemp; i++)
  7638. {
  7639. siz.cx = arclTemp[i].right - arclTemp[i].left;
  7640. siz.cy = arclTemp[i].bottom - arclTemp[i].top;
  7641. if (pState->ahDragSprite[i])
  7642. {
  7643. GreUpdateSprite(hdev,
  7644. NULL,
  7645. pState->ahDragSprite[i],
  7646. NULL,
  7647. (POINT*) &arclTemp[i],
  7648. &siz,
  7649. NULL,
  7650. NULL,
  7651. NULL,
  7652. NULL,
  7653. ULW_DRAGRECT,
  7654. NULL);
  7655. }
  7656. }
  7657. for (; i < 4; i++)
  7658. {
  7659. if (pState->ahDragSprite[i])
  7660. {
  7661. GreUpdateSprite(hdev, NULL, pState->ahDragSprite[i], NULL, NULL,
  7662. NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  7663. }
  7664. }
  7665. return(TRUE);
  7666. }
  7667. /******************************Public*Routine******************************\
  7668. * BOOL bSetDevDragRect
  7669. *
  7670. * Called by USER to slap the drag rect on the screen, or to tear it back
  7671. * down.
  7672. *
  7673. * History:
  7674. * 4-Apr-1998 -by- J. Andrew Goossen andrewgo
  7675. * Converted drag rects to use sprites.
  7676. \**************************************************************************/
  7677. BOOL bSetDevDragRect(
  7678. HDEV hdev, // Note that this may be a multi-mon meta-PDEV
  7679. RECTL* prclDrag,
  7680. RECTL* prclClip)
  7681. {
  7682. SPRITESTATE* pState;
  7683. RECTL rclScreen;
  7684. RECTL arclDrag[4];
  7685. ULONG crclDrag;
  7686. HANDLE hSprite;
  7687. ULONG i;
  7688. BOOL bRet = TRUE; // Assume success
  7689. PDEVOBJ po(hdev);
  7690. pState = po.pSpriteState();
  7691. DEVLOCKOBJ dlo(po);
  7692. pState->bHaveDragRect = FALSE;
  7693. // Create 4 sprites to handle each of the sides of the drag rectangle.
  7694. if (prclDrag != NULL)
  7695. {
  7696. ASSERTGDI(!pState->bHaveDragRect, "Expected not to have a drag rectangle");
  7697. ASSERTGDI(prclClip != NULL, "Expected to have a clip rectangle");
  7698. bRet = TRUE;
  7699. for (i = 0; i < 4; i++)
  7700. {
  7701. hSprite = GreCreateSprite(hdev, NULL, NULL);
  7702. pState->ahDragSprite[i] = hSprite;
  7703. if (!hSprite)
  7704. bRet = FALSE;
  7705. }
  7706. if (bRet)
  7707. {
  7708. pState->bHaveDragRect = TRUE;
  7709. pState->rclDragClip = *prclClip;
  7710. bMoveDevDragRect(hdev, prclDrag);
  7711. }
  7712. }
  7713. // If we don't have a drag rectangle, delete any drag rectangle
  7714. // sprites we may have laying around.
  7715. if (!pState->bHaveDragRect)
  7716. {
  7717. for (i = 0; i < 4; i++)
  7718. {
  7719. if (pState->ahDragSprite[i] != NULL)
  7720. {
  7721. GreDeleteSprite(hdev, NULL, pState->ahDragSprite[i]);
  7722. pState->ahDragSprite[i] = NULL;
  7723. }
  7724. }
  7725. }
  7726. return(bRet);
  7727. }
  7728. /******************************Public*Routine******************************\
  7729. * BOOL bSetDevDragWidth
  7730. *
  7731. * Called by USER to tell us how wide the drag rectangle should be.
  7732. *
  7733. * 24-Aug-1992 -by- Patrick Haluptzok patrickh
  7734. * Wrote it.
  7735. \**************************************************************************/
  7736. BOOL bSetDevDragWidth(
  7737. HDEV hdev,
  7738. ULONG ulWidth)
  7739. {
  7740. PDEVOBJ po(hdev);
  7741. DEVLOCKOBJ dlo(po);
  7742. SPRITESTATE* pState = po.pSpriteState();
  7743. pState->ulDragDimension = ulWidth;
  7744. return(TRUE);
  7745. }
  7746. /******************************Public*Routine******************************\
  7747. * UNDODESKTOPCOORD
  7748. *
  7749. * Temporariliy convert the WNDOBJ from desktop coordinates to device-
  7750. * relative coordinates.
  7751. *
  7752. * History:
  7753. * 4-Apr-1998 -by- J. Andrew Goossen andrewgo
  7754. \**************************************************************************/
  7755. UNDODESKTOPCOORD::UNDODESKTOPCOORD(
  7756. EWNDOBJ* pwo,
  7757. SPRITESTATE* pState)
  7758. {
  7759. pwoUndo = NULL;
  7760. if ((pwo != NULL) && (pwo->fl & WO_RGN_DESKTOP_COORD))
  7761. {
  7762. PDEVOBJ po(pState->hdev);
  7763. po.vAssertDevLock();
  7764. pwoUndo = pwo;
  7765. xUndo = po.pptlOrigin()->x;
  7766. yUndo = po.pptlOrigin()->y;
  7767. pwo->vOffset(-xUndo, -yUndo);
  7768. pwo->fl &= ~WO_RGN_DESKTOP_COORD;
  7769. }
  7770. }
  7771. /******************************Public*Routine******************************\
  7772. * VOID vSpDeviceControlSprites
  7773. *
  7774. * Undo our temporary conversion of a WNDOBJ to device-relative coordinates.
  7775. *
  7776. * History:
  7777. * 4-Apr-1998 -by- J. Andrew Goossen andrewgo
  7778. \**************************************************************************/
  7779. UNDODESKTOPCOORD::~UNDODESKTOPCOORD()
  7780. {
  7781. if (pwoUndo)
  7782. {
  7783. pwoUndo->vOffset(xUndo, yUndo);
  7784. pwoUndo->fl |= WO_RGN_DESKTOP_COORD;
  7785. }
  7786. }
  7787. /******************************Public*Routine******************************\
  7788. * VOID vSpDeviceControlSprites
  7789. *
  7790. * Function callable from the driver to control the exclusion of sprites
  7791. * from on top of a WNDOBJ window.
  7792. *
  7793. * History:
  7794. * 4-Apr-1998 -by- J. Andrew Goossen andrewgo
  7795. \**************************************************************************/
  7796. VOID vSpDeviceControlSprites(
  7797. HDEV hdev,
  7798. EWNDOBJ* pwo,
  7799. FLONG fl)
  7800. {
  7801. SPRITESTATE* pState;
  7802. BOOL bMore;
  7803. SPRITE* pSprite;
  7804. RECTL rclEnum;
  7805. RECTL rclBounds;
  7806. PDEVOBJ po(hdev);
  7807. po.vAssertDevLock();
  7808. SPRITELOCK slock(po);
  7809. pState = po.pSpriteState();
  7810. // The WNDOBJ coordinates must be device-relative, so
  7811. // use UNDO:
  7812. UNDODESKTOPCOORD udc(pwo, pState);
  7813. if (fl == ECS_TEARDOWN)
  7814. {
  7815. pwo->fl |= WO_NOSPRITES;
  7816. // We only have to do some work if a sprite overlaps the
  7817. // window:
  7818. if ((pwo->fl & WO_SPRITE_OVERLAP) &&
  7819. bIntersect(&pwo->rclBounds, &pState->rclScreen, &rclBounds))
  7820. {
  7821. // Tear down all sprites:
  7822. ENUMAREAS Enum(pState, &rclBounds);
  7823. do {
  7824. bMore = Enum.bEnum(&pSprite, &rclEnum);
  7825. if (pSprite != NULL)
  7826. {
  7827. OFFCOPYBITS(&gptlZero,
  7828. pState->psoScreen,
  7829. &pSprite->OffUnderlay,
  7830. pSprite->psoUnderlay,
  7831. pwo,
  7832. NULL,
  7833. &rclEnum,
  7834. (POINTL*) &rclEnum);
  7835. }
  7836. } while (bMore);
  7837. }
  7838. // Now that we're done tearing down, re-compute the
  7839. // unlocked region, to account for the newly locked
  7840. // area.
  7841. vSpComputeUnlockedRegion(pState);
  7842. }
  7843. else
  7844. {
  7845. // Note that it's perfectly fine to call 'redraw' without having
  7846. // first done 'teardown' (this is useful for OpenGL windows when
  7847. // hardware double buffering, in order to prevent the cursor from
  7848. // flickering).
  7849. pwo->fl &= ~WO_NOSPRITES;
  7850. // Re-compute the unlocked region, to account for the changed
  7851. // state.
  7852. vSpComputeUnlockedRegion(pState);
  7853. if ((pwo->fl & WO_SPRITE_OVERLAP) &&
  7854. bIntersect(&pwo->rclBounds, &pState->rclScreen, &rclBounds))
  7855. {
  7856. // First, get the new underlay bits:
  7857. ENUMAREAS Enum(pState, &rclBounds);
  7858. do {
  7859. bMore = Enum.bEnum(&pSprite, &rclEnum);
  7860. if (pSprite != NULL)
  7861. {
  7862. // All underlays which overlap with this area must be
  7863. // updated, which explains the following 'bEnumLayers':
  7864. do {
  7865. OFFCOPYBITS(&pSprite->OffUnderlay,
  7866. pSprite->psoUnderlay,
  7867. &gptlZero,
  7868. pState->psoScreen,
  7869. pwo,
  7870. NULL,
  7871. &rclEnum,
  7872. (POINTL*) &rclEnum);
  7873. } while (Enum.bEnumLayers(&pSprite));
  7874. }
  7875. } while (bMore);
  7876. // Now draw the sprites:
  7877. vSpRedrawArea(pState, &rclBounds, TRUE);
  7878. }
  7879. }
  7880. }
  7881. /******************************Public*Routine******************************\
  7882. * BOOL EngControlSprites
  7883. *
  7884. * Multi-mon aware function that's callable from the driver to control the
  7885. * exclusion of sprites from on top of a WNDOBJ window.
  7886. *
  7887. * History:
  7888. * 4-Apr-1998 -by- J. Andrew Goossen andrewgo
  7889. \**************************************************************************/
  7890. BOOL EngControlSprites(
  7891. WNDOBJ* pwo,
  7892. FLONG fl)
  7893. {
  7894. SPRITESTATE* pState;
  7895. ULONG i;
  7896. if ((fl != ECS_TEARDOWN) && (fl != ECS_REDRAW))
  7897. return(FALSE);
  7898. PDEVOBJ po(((EWNDOBJ*) pwo)->pto->pSurface->hdev());
  7899. PDEVOBJ poParent(po.hdevParent());
  7900. DEVLOCKOBJ dlo(po);
  7901. pState = poParent.pSpriteState();
  7902. if (pState->cMultiMon)
  7903. {
  7904. for (i = 0; i < pState->cMultiMon; i++)
  7905. {
  7906. vSpDeviceControlSprites(pState->ahdevMultiMon[i], (EWNDOBJ*) pwo, fl);
  7907. }
  7908. }
  7909. else
  7910. {
  7911. vSpDeviceControlSprites(po.hdev(), (EWNDOBJ*) pwo, fl);
  7912. }
  7913. return(TRUE);
  7914. }
  7915. /******************************Public*Routine******************************\
  7916. * VOID vSpComputeUnlockedRegion
  7917. *
  7918. * Compute the region that describes the area on which sprites are free
  7919. * to draw (which does not include DirectDraw locked areas, or WNDOBJ
  7920. * areas that have the WO_NOSPRITES flag set).
  7921. *
  7922. * History:
  7923. * 4-Apr-1998 -by- J. Andrew Goossen andrewgo
  7924. \**************************************************************************/
  7925. VOID vSpComputeUnlockedRegion(
  7926. SPRITESTATE* pState)
  7927. {
  7928. RECTL rcl;
  7929. SURFACE* pSurface;
  7930. TRACKOBJ* pto;
  7931. EWNDOBJ* pwo;
  7932. PDEVOBJ po(pState->hdev);
  7933. po.vAssertDevLock();
  7934. // Get rid of the old region:
  7935. if (pState->prgnUnlocked != NULL)
  7936. {
  7937. pState->prgnUnlocked->vDeleteREGION();
  7938. pState->prgnUnlocked = NULL;
  7939. }
  7940. pSurface = SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen);
  7941. // We have to to work if either a DirectDraw lock is active, or if a
  7942. // WNDOBJ is active.
  7943. if ((DxDdGetSurfaceLock(po.hdev()) || gpto != NULL))
  7944. {
  7945. // Calculate the new region:
  7946. RGNMEMOBJ rmoUnlocked((BOOL) FALSE);
  7947. if (rmoUnlocked.bValid())
  7948. {
  7949. rcl.left = 0;
  7950. rcl.top = 0;
  7951. rcl.right = po.sizl().cx;
  7952. rcl.bottom = po.sizl().cy;
  7953. rmoUnlocked.vSet(&rcl);
  7954. RGNMEMOBJTMP rmoRect((BOOL) FALSE);
  7955. RGNMEMOBJTMP rmoTmp((BOOL) FALSE);
  7956. if (rmoRect.bValid() && rmoTmp.bValid())
  7957. {
  7958. // Loop through the list of DirectDraw locked surfaces and
  7959. // remove their locked rectangles from the inclusion region:
  7960. RECTL rclDdLocked;
  7961. PVOID pvDdSurface = DxDdEnumLockedSurfaceRect(po.hdev(),NULL,&rclDdLocked);
  7962. while (pvDdSurface)
  7963. {
  7964. // We don't check the return code on 'bCopy' because it
  7965. // guarantees that it will maintain valid region constructs
  7966. // -- even if the contents are incorrect. And if we fail
  7967. // here because we're low on memory, it's guaranteed that
  7968. // there will already be plenty of incorrect drawing,
  7969. // so we don't care if our inclusion region is
  7970. // invalid:
  7971. rmoRect.vSet(&rclDdLocked);
  7972. rmoTmp.bCopy(rmoUnlocked);
  7973. if (!rmoUnlocked.bMerge(rmoTmp, rmoRect, gafjRgnOp[RGN_DIFF]))
  7974. {
  7975. rmoUnlocked.vSet();
  7976. }
  7977. // Move on to next surface.
  7978. pvDdSurface = DxDdEnumLockedSurfaceRect(po.hdev(),pvDdSurface,&rclDdLocked);
  7979. }
  7980. // We must be holding the WNDOBJ semaphore before mucking
  7981. // with any WNDOBJs.
  7982. SEMOBJ so(ghsemWndobj);
  7983. // Now loop through the list of WNDOBJs, and subtract their
  7984. // regions.
  7985. for (pto = gpto; pto; pto = pto->ptoNext)
  7986. {
  7987. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  7988. {
  7989. // The WNDOBJ coordinates must be device-relative, so
  7990. // use UNDO:
  7991. UNDODESKTOPCOORD udc(pwo, pState);
  7992. if (pwo->fl & WO_NOSPRITES)
  7993. {
  7994. rmoTmp.bCopy(rmoUnlocked);
  7995. if (!rmoUnlocked.bMerge(rmoTmp,
  7996. *pwo,
  7997. gafjRgnOp[RGN_DIFF]))
  7998. {
  7999. rmoUnlocked.vSet();
  8000. }
  8001. }
  8002. }
  8003. }
  8004. }
  8005. rmoUnlocked.vStamp();
  8006. pState->prgnUnlocked = rmoUnlocked.prgnGet();
  8007. }
  8008. }
  8009. // Finally, mark the range cache as invalid so that 'prgnUncovered'
  8010. // gets recomputed to incorporate 'prgnUnlocked':
  8011. pState->bValidRange = FALSE;
  8012. }
  8013. /******************************Public*Routine******************************\
  8014. * VOID vSpUpdateWndobjOverlap
  8015. *
  8016. * Recalculate whether any sprites overlap a WNDOBJ area, and notify the
  8017. * driver if that state has changed.
  8018. *
  8019. * History:
  8020. * 4-Apr-1998 -by- J. Andrew Goossen andrewgo
  8021. \**************************************************************************/
  8022. VOID vSpUpdateWndobjOverlap(
  8023. SPRITESTATE* pState,
  8024. EWNDOBJ* pwo)
  8025. {
  8026. BOOL bSpriteOverlap;
  8027. SPRITE* pSprite;
  8028. PDEVOBJ po(pState->hdev);
  8029. po.vAssertDevLock();
  8030. ASSERTGDI(!(pwo->fl & WO_RGN_DESKTOP_COORD), "Use UNDODESKTOPCOORD");
  8031. // Ah ha. Recalculate total number of intersections for
  8032. // this WNDOBJ.
  8033. bSpriteOverlap = FALSE;
  8034. for (pSprite = pState->pListZ;
  8035. pSprite != NULL;
  8036. pSprite = pSprite->pNextZ)
  8037. {
  8038. if (bIntersect(&pwo->rclBounds, &pSprite->rclSprite))
  8039. {
  8040. if (pwo->bInside(&pSprite->rclSprite) == REGION_RECT_INTERSECT)
  8041. {
  8042. RGNOBJ roClip(pSprite->prgnClip);
  8043. if (!roClip.bValid() ||
  8044. (roClip.bInside(&pwo->rclBounds) == REGION_RECT_INTERSECT))
  8045. {
  8046. bSpriteOverlap = TRUE;
  8047. break;
  8048. }
  8049. }
  8050. }
  8051. }
  8052. // Inform the driver if the overlap state for this window
  8053. // has changed.
  8054. if ((bSpriteOverlap) && !(pwo->fl & WO_SPRITE_OVERLAP))
  8055. {
  8056. pwo->fl |= WO_SPRITE_OVERLAP;
  8057. if (pwo->fl & WO_SPRITE_NOTIFY)
  8058. pwo->pto->vUpdateDrv(pwo, WOC_SPRITE_OVERLAP);
  8059. }
  8060. else if ((!bSpriteOverlap) && (pwo->fl & WO_SPRITE_OVERLAP))
  8061. {
  8062. pwo->fl &= ~WO_SPRITE_OVERLAP;
  8063. if (pwo->fl & WO_SPRITE_NOTIFY)
  8064. pwo->pto->vUpdateDrv(pwo, WOC_SPRITE_NO_OVERLAP);
  8065. }
  8066. }
  8067. /******************************Public*Routine******************************\
  8068. * VOID vSpCheckForWndobjOverlap
  8069. *
  8070. * Go through all the WNDOBJs and see if either the old or the new sprite
  8071. * position may have changed the sprite overlap state.
  8072. *
  8073. * History:
  8074. * 4-Apr-1998 -by- J. Andrew Goossen andrewgo
  8075. \**************************************************************************/
  8076. VOID vSpCheckForWndobjOverlap(
  8077. SPRITESTATE* pState,
  8078. RECTL* prclNew,
  8079. RECTL* prclOld)
  8080. {
  8081. SURFACE* pSurface;
  8082. TRACKOBJ* pto;
  8083. EWNDOBJ* pwo;
  8084. PDEVOBJ po(pState->hdev);
  8085. po.vAssertDevLock();
  8086. pSurface = SURFOBJ_TO_SURFACE_NOT_NULL(pState->psoScreen);
  8087. // Hold the WNDOBJ semaphore before mucking with any WNDOBJs.
  8088. SEMOBJ so(ghsemWndobj);
  8089. for (pto = gpto; pto; pto = pto->ptoNext)
  8090. {
  8091. for (pwo = pto->pwo; pwo; pwo = pwo->pwoNext)
  8092. {
  8093. // The WNDOBJ coordinates must be device-relative, so use UNDO:
  8094. UNDODESKTOPCOORD udc(pwo, pState);
  8095. // Note that this cannot be an 'XOR' test, because we're
  8096. // only testing the bounds at this point.
  8097. if (bIntersect(&pwo->rclBounds, prclNew) ||
  8098. bIntersect(&pwo->rclBounds, prclOld))
  8099. {
  8100. vSpUpdateWndobjOverlap(pState, pwo);
  8101. }
  8102. }
  8103. }
  8104. }
  8105. /******************************Public*Routine******************************\
  8106. * VOID vSpDeviceWndobjChange
  8107. *
  8108. * Routine to inform the sprite code when a WNDOBJ has changed.
  8109. *
  8110. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  8111. * Wrote it.
  8112. \**************************************************************************/
  8113. VOID vSpDeviceWndobjChange(
  8114. HDEV hdev,
  8115. EWNDOBJ* pwo)
  8116. {
  8117. SPRITESTATE* pState;
  8118. PDEVOBJ po(hdev);
  8119. pState = po.pSpriteState();
  8120. // The WNDOBJ coordinates must be device-relative, so use UNDO:
  8121. UNDODESKTOPCOORD udc(pwo, pState);
  8122. po.vAssertDevLock();
  8123. if (pwo != NULL)
  8124. {
  8125. vSpUpdateWndobjOverlap(pState, pwo);
  8126. }
  8127. // Technically, we only have to recompute the regions when a WO_NOSPRITE
  8128. // WNDOBJ has been created, destroyed, or moved. But it won't hurt
  8129. // anything if we do it for any WNDOBJ.
  8130. vSpComputeUnlockedRegion(pState);
  8131. }
  8132. /******************************Public*Routine******************************\
  8133. * VOID vSpWndobjChange
  8134. *
  8135. * Routine to inform the sprite code when a WNDOBJ has changed. This
  8136. * routine is multi-mon aware.
  8137. *
  8138. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  8139. * Wrote it.
  8140. \**************************************************************************/
  8141. VOID vSpWndobjChange(
  8142. HDEV hdev,
  8143. EWNDOBJ* pwo)
  8144. {
  8145. SPRITESTATE* pState;
  8146. ULONG i;
  8147. PDEVOBJ po(hdev);
  8148. DEVLOCKOBJ dlo(po);
  8149. pState = po.pSpriteState();
  8150. if (pState->cMultiMon)
  8151. {
  8152. for (i = 0; i < pState->cMultiMon; i++)
  8153. {
  8154. vSpDeviceWndobjChange(pState->ahdevMultiMon[i], pwo);
  8155. }
  8156. }
  8157. else
  8158. {
  8159. vSpDeviceWndobjChange(hdev, pwo);
  8160. }
  8161. }
  8162. /******************************Public*Routine******************************\
  8163. * BOOL bSpTearDownSprites
  8164. *
  8165. * This routine tears-down any sprites in the specified rectangle.
  8166. *
  8167. * Returns: TRUE if any sprites were torn down (and so need to be re-drawn
  8168. * later), FALSE if no sprites were torn down.
  8169. *
  8170. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  8171. * Wrote it.
  8172. \**************************************************************************/
  8173. BOOL bSpTearDownSprites(
  8174. HDEV hdev,
  8175. RECTL* prclExclude,
  8176. BOOL bDirectDrawLock) // TRUE if we're being called by the DirectDraw
  8177. // Lock function. FALSE if we're being called
  8178. // from a routine which wants to just
  8179. // momentarily tear down the sprite
  8180. {
  8181. SPRITESTATE* pState;
  8182. RECTL rclEnum;
  8183. BOOL bTearDown;
  8184. BOOL bMore;
  8185. SPRITE* pSprite;
  8186. RECTL rclExclude;
  8187. PDEVOBJ po(hdev);
  8188. // No sprites to tear down on printers
  8189. if (!po.bDisplayPDEV())
  8190. {
  8191. return FALSE;
  8192. }
  8193. po.vAssertDevLock();
  8194. pState = po.pSpriteState();
  8195. SPRITELOCK slock(po);
  8196. bTearDown = FALSE;
  8197. // We only need to do any actual work if any sprites are up on
  8198. // the screen:
  8199. if (pState->cVisible != 0)
  8200. {
  8201. if (bIntersect(prclExclude, &pState->rclScreen, &rclExclude))
  8202. {
  8203. // Tear down all sprites:
  8204. ENUMAREAS Enum(pState, &rclExclude);
  8205. do {
  8206. bMore = Enum.bEnum(&pSprite, &rclEnum);
  8207. if (pSprite != NULL)
  8208. {
  8209. bTearDown = TRUE;
  8210. vSpWriteToScreen(pState,
  8211. &pSprite->OffUnderlay,
  8212. pSprite->psoUnderlay,
  8213. &rclEnum);
  8214. }
  8215. } while (bMore);
  8216. if (bDirectDrawLock)
  8217. {
  8218. // Now compute the new unlocked region:
  8219. vSpComputeUnlockedRegion(pState);
  8220. }
  8221. }
  8222. }
  8223. return(bTearDown);
  8224. }
  8225. /******************************Public*Routine******************************\
  8226. * VOID vSpUnTearDownSprites
  8227. *
  8228. * This routine redraws any sprites in the specified rectangle.
  8229. *
  8230. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  8231. * Wrote it.
  8232. \**************************************************************************/
  8233. VOID vSpUnTearDownSprites(
  8234. HDEV hdev,
  8235. RECTL* prclExclude,
  8236. BOOL bDirectDrawUnlock)
  8237. {
  8238. SPRITESTATE* pState;
  8239. RECTL rclEnum;
  8240. BOOL bMore;
  8241. SPRITE* pSprite;
  8242. RECTL rclExclude;
  8243. PDEVOBJ po(hdev);
  8244. ASSERTGDI(po.bDisplayPDEV(), "vSpUnTearDownSprites: not a display pdev");
  8245. po.vAssertDevLock();
  8246. pState = po.pSpriteState();
  8247. // We only need to do any actual work if any sprites are up on
  8248. // the screen:
  8249. if (pState->cVisible != 0)
  8250. {
  8251. if (bIntersect(prclExclude, &pState->rclScreen, &rclExclude))
  8252. {
  8253. SPRITELOCK slock(po);
  8254. if (bDirectDrawUnlock)
  8255. {
  8256. // Now compute the new unlocked region:
  8257. vSpComputeUnlockedRegion(pState);
  8258. }
  8259. // Reload the underlays:
  8260. ENUMAREAS Enum(pState, &rclExclude);
  8261. do {
  8262. // We know that we already excluded any sprites from the
  8263. // 'prclExclude' area, so it's safe to update the underlays
  8264. // directly from the screen since we know we won't pick up
  8265. // any sprite images.
  8266. bMore = Enum.bEnum(&pSprite, &rclEnum);
  8267. if (pSprite != NULL)
  8268. {
  8269. do {
  8270. vSpReadFromScreen(pState,
  8271. &pSprite->OffUnderlay,
  8272. pSprite->psoUnderlay,
  8273. &rclEnum);
  8274. } while (Enum.bEnumLayers(&pSprite));
  8275. }
  8276. } while (bMore);
  8277. // Redraw the affected area:
  8278. vSpRedrawArea(pState, &rclExclude, TRUE);
  8279. }
  8280. }
  8281. }
  8282. /******************************Public*Routine******************************\
  8283. * BOOL bSpSpritesVisible
  8284. *
  8285. * Returns TRUE if any emulated sprites are currently visible.
  8286. *
  8287. * 16-Sep-1997 -by- J. Andrew Goossen [andrewgo]
  8288. * Wrote it.
  8289. \**************************************************************************/
  8290. BOOL bSpSpritesVisible(
  8291. HDEV hdev)
  8292. {
  8293. SPRITESTATE* pState;
  8294. PDEVOBJ po(hdev);
  8295. po.vAssertDevLock();
  8296. pState = po.pSpriteState();
  8297. return(pState->cVisible != 0);
  8298. }