mouse.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. //===========================================================================//
  2. // Copyright (C) Microsoft Corporation. All rights reserved. //
  3. //===========================================================================//
  4. //-------------------------------------------------------------------
  5. //
  6. // This code will run in a separate callback to update the mouse
  7. // positions at a fixed frame rate which is different from the game's
  8. //
  9. // Essential for software and low frame rate situations
  10. //
  11. // Code is actually fairly simple BUT must work right ALL the time.
  12. // As usual, debugging when a lock has been taken is often VERY hard.
  13. //
  14. // For each trip through the callback:
  15. // -if Screen has not been flipped since we were last here...
  16. // -Lock Rect Cursor WAS in.
  17. // -BLT old screen contents from mouseBuffer.
  18. // -Unlock Rect Cursor WAS in.
  19. // -Get Current Mouse X and Y.
  20. // -Lock Rect Cursor IS in.
  21. // -Copy Screen Contents of Rect to mouseBuffer.
  22. // -BLT mouse cursor to Rect.
  23. // -Unlock Rect Cursor IS in.
  24. //
  25. // We should run this at a fixed rate of 10 to 20 Hz.
  26. //
  27. // This MUST block GameOS DisplayBackBuffer AND must NOT be called
  28. // DURING GameOS DisplayBackBuffer.
  29. //
  30. // Cursors must be stored in a BLTable format for speed purposes. 32Bit TGA OK?
  31. //
  32. // Cursors must NOT be anything BUT keyed from now on.
  33. //
  34. // DisplayBackBuffer MUST do the following AFTER everything is done rendering
  35. // and BEFORE it flips its buffers:
  36. // -Get Current Mouse X and Y.
  37. // -Lock Rect of BACKBUFFER Cursor IS in.
  38. // -Copy Screen Contents of Rect to mouseBuffer.
  39. // -BLT mouse cursor to Rect.
  40. // -Unlock Rect Cursor IS in.
  41. //
  42. //
  43. //-----------------------------------------------------------------------
  44. #include "dstd.h"
  45. #include "userinput.h"
  46. #include <windows.h>
  47. #include <mmsystem.h>
  48. #include <ddraw.h>
  49. #include <gameos.hpp>
  50. extern volatile bool mc2IsInDisplayBackBuffer;
  51. extern volatile bool mc2IsInMouseTimer;
  52. extern volatile bool mc2DisplayHasFlipped;
  53. extern volatile bool mc2HasLostFocus;
  54. volatile bool mc2MouseThreadStarted = false;
  55. volatile bool mc2UseAsyncMouse = true;
  56. MemoryPtr mouseBuffer = NULL;
  57. MMRESULT HTimer = 0;
  58. RECT mouseWASInRect;
  59. volatile char mc2MouseHotSpotX = 0;
  60. volatile char mc2MouseHotSpotY = 0;
  61. volatile char mc2MouseWidth = 32;
  62. volatile char mc2MouseHeight = 32;
  63. volatile MemoryPtr mc2MouseData = NULL;
  64. //Timing in Hz to update mouse
  65. long MOUSE_REFRESH_RATE = 30;
  66. void CALLBACK MouseTimer(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2);
  67. void (*AsynFunc)(RECT& WinRect,DDSURFACEDESC2& mouseSurfaceDesc ) = 0;
  68. //External GameOS stuff
  69. extern IDirectDrawSurface7* FrontBufferSurface;
  70. extern HWND hWindow;
  71. extern POINT clientToScreen;
  72. extern DWORD MouseInWindow;
  73. //
  74. // Init the Mouse timer
  75. //
  76. void MouseTimerInit()
  77. {
  78. //Create mouseBuffer to hold screen contents under the mouse cursor.
  79. // This buffer MUST be at bit depth of screen!!
  80. // OR we could create a 32Bit buffer and convert during Blts both ways.
  81. // FASTEST would be created to screen Bit Depth BUT this means that
  82. // the mouseBuffer must be recreated if we change to 32 bit rendering.
  83. // Should we even allow changing to 32-Bit Rendering?
  84. //
  85. // For now, create a 32Bit buffer and convert as needed. If speed is an
  86. // issue on low end stuff, change it out.
  87. //
  88. mouseBuffer = (MemoryPtr)malloc(sizeof(DWORD) * MOUSE_WIDTH * MOUSE_WIDTH);
  89. memset(mouseBuffer,0,sizeof(DWORD) * MOUSE_WIDTH * MOUSE_WIDTH);
  90. if (!mc2MouseData)
  91. {
  92. mc2MouseData = (MemoryPtr)malloc(sizeof(DWORD) * MOUSE_WIDTH * MOUSE_WIDTH);
  93. memset(mc2MouseData,0,sizeof(DWORD) * MOUSE_WIDTH * MOUSE_WIDTH);
  94. }
  95. mc2MouseThreadStarted = true;
  96. mc2DisplayHasFlipped = true;
  97. mouseWASInRect.top = 0;
  98. mouseWASInRect.left = 0;
  99. mouseWASInRect.right = 32;
  100. mouseWASInRect.bottom = 32;
  101. HTimer=timeSetEvent( 1000/MOUSE_REFRESH_RATE, 0, (LPTIMECALLBACK)MouseTimer, 0, TIME_PERIODIC );
  102. }
  103. //
  104. // Clean up the mouse timer
  105. //
  106. void MouseTimerKill()
  107. {
  108. if(HTimer)
  109. {
  110. while (mc2IsInMouseTimer)
  111. ;
  112. timeKillEvent(HTimer);
  113. while (mc2IsInMouseTimer)
  114. ;
  115. HTimer=0;
  116. }
  117. mc2MouseThreadStarted = false; //Keep us from calling silly stuff during startup and shutdown if we exception
  118. free(mouseBuffer);
  119. mouseBuffer = NULL;
  120. free(mc2MouseData);
  121. mc2MouseData = NULL;
  122. }
  123. //
  124. // Returns the number of bits in a given mask. Used to determine if we are in 555 mode vs 565 mode.
  125. WORD GetNumberOfBits( DWORD dwMask )
  126. {
  127. WORD wBits = 0;
  128. while( dwMask )
  129. {
  130. dwMask = dwMask & ( dwMask - 1 );
  131. wBits++;
  132. }
  133. return wBits;
  134. }
  135. //
  136. // Actual Mouse Callback code here.
  137. //
  138. void CALLBACK MouseTimer(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
  139. {
  140. HRESULT lockResult = -1;
  141. HRESULT unlockResult = -1;
  142. RECT WinRect;
  143. DDSURFACEDESC2 mouseSurfaceDesc;
  144. mouseSurfaceDesc.dwSize = sizeof(DDSURFACEDESC2);
  145. long screenX = Environment.screenWidth;
  146. long screenY = Environment.screenHeight;
  147. //Must immediately get out, We are NOT the main app anymore!!
  148. if (mc2HasLostFocus)
  149. return;
  150. //Must immediately get out if are Flipping or Blting the display!!
  151. if (mc2IsInDisplayBackBuffer)
  152. return;
  153. //Called this while we are already in it, let it finish the last request first!!
  154. if (mc2IsInMouseTimer)
  155. return;
  156. //Thread hasn't started yet? Should not be possible but insure safety.
  157. // These mouse thingies are NOTORIOUSLY hard to debug!!
  158. if (!mc2MouseThreadStarted)
  159. return;
  160. //For some unknown reason, our offscreen buffer is now NULL. DO not allow this to run!!
  161. if (!mouseBuffer)
  162. return;
  163. //Warn everyone that we are updating the mouse now.
  164. // If we get to DisplayBackBuffer and this is true, WAIT until it goes false!!
  165. mc2IsInMouseTimer = true;
  166. //
  167. // Create a Rect with the actual screen dimensions in it.
  168. //
  169. if( Environment.fullScreen )
  170. {
  171. GetWindowRect( hWindow, &WinRect );
  172. }
  173. else
  174. {
  175. WinRect.top = clientToScreen.y+1;
  176. WinRect.left = clientToScreen.x+1;
  177. WinRect.right = clientToScreen.x + Environment.screenWidth - 1;
  178. WinRect.bottom = clientToScreen.y + Environment.screenHeight - 1;
  179. }
  180. // -if Screen has not been flipped since we were last here...
  181. if (!mc2DisplayHasFlipped)
  182. {
  183. // -Lock Rect Cursor WAS in.
  184. if (FrontBufferSurface)
  185. lockResult = FrontBufferSurface->Lock(NULL,&mouseSurfaceDesc,DDLOCK_DONOTWAIT,NULL);
  186. else
  187. lockResult = -1;
  188. if (lockResult == DD_OK)
  189. {
  190. // call other functions first if any
  191. if ( AsynFunc )
  192. AsynFunc( WinRect, mouseSurfaceDesc );
  193. if (UserInput::drawMouse)
  194. {
  195. //Good. Surface was ready to be locked, BLT our mouseBuffer to it.
  196. // -BLT old screen contents from mouseBuffer.
  197. //
  198. // Get the pixel Format and use it to copy data from the mouseBuffer
  199. // to the screen.
  200. if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 16)
  201. {
  202. MemoryPtr mBuffer = mouseBuffer;
  203. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  204. {
  205. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  206. ((mouseWASInRect.left << 1) +
  207. (y * mouseSurfaceDesc.lPitch));
  208. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  209. {
  210. //Only copy bytes that are on screen.
  211. if ((x > WinRect.left) && (y > WinRect.top))
  212. {
  213. //Copy first byte
  214. *screenPos = *mBuffer;
  215. mBuffer++;
  216. screenPos++;
  217. //Copy second byte
  218. *screenPos = *mBuffer;
  219. mBuffer++;
  220. screenPos++;
  221. }
  222. else
  223. {
  224. //Just iterate across the screen and buffer
  225. //
  226. //Skip first byte
  227. mBuffer++;
  228. screenPos++;
  229. //Skip second byte
  230. mBuffer++;
  231. screenPos++;
  232. }
  233. }
  234. }
  235. }
  236. else if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 24)
  237. {
  238. MemoryPtr mBuffer = mouseBuffer;
  239. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  240. {
  241. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  242. ((mouseWASInRect.left * 3) +
  243. (y * mouseSurfaceDesc.lPitch));
  244. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  245. {
  246. //Only copy bytes that are on screen.
  247. if ((x > WinRect.left) && (y > WinRect.top))
  248. {
  249. //Copy first byte
  250. *screenPos = *mBuffer;
  251. mBuffer++;
  252. screenPos++;
  253. //Copy second byte
  254. *screenPos = *mBuffer;
  255. mBuffer++;
  256. screenPos++;
  257. //Copy third byte
  258. *screenPos = *mBuffer;
  259. mBuffer++;
  260. screenPos++;
  261. }
  262. else
  263. {
  264. //Just iterate across the screen and buffer
  265. //
  266. //Skip first byte
  267. mBuffer++;
  268. screenPos++;
  269. //Skip second byte
  270. mBuffer++;
  271. screenPos++;
  272. //Skip third byte
  273. mBuffer++;
  274. screenPos++;
  275. }
  276. }
  277. }
  278. }
  279. else if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 32)
  280. {
  281. MemoryPtr mBuffer = mouseBuffer;
  282. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  283. {
  284. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  285. ((mouseWASInRect.left << 2) +
  286. (y * mouseSurfaceDesc.lPitch));
  287. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  288. {
  289. //Only copy bytes that are on screen.
  290. if ((x > WinRect.left) && (y > WinRect.top))
  291. {
  292. //Copy first byte
  293. *screenPos = *mBuffer;
  294. mBuffer++;
  295. screenPos++;
  296. //Copy second byte
  297. *screenPos = *mBuffer;
  298. mBuffer++;
  299. screenPos++;
  300. //Copy third byte
  301. *screenPos = *mBuffer;
  302. mBuffer++;
  303. screenPos++;
  304. //Copy fourth byte
  305. *screenPos = *mBuffer;
  306. mBuffer++;
  307. screenPos++;
  308. }
  309. else
  310. {
  311. //Just iterate across the screen and buffer
  312. //
  313. //Skip first byte
  314. mBuffer++;
  315. screenPos++;
  316. //Skip second byte
  317. mBuffer++;
  318. screenPos++;
  319. //Skip third byte
  320. mBuffer++;
  321. screenPos++;
  322. //Skip fourth byte
  323. mBuffer++;
  324. screenPos++;
  325. }
  326. }
  327. }
  328. }
  329. else
  330. {
  331. //We are in some WAY unknown video mode. Just get out.
  332. unlockResult = FrontBufferSurface->Unlock(&mouseWASInRect);
  333. if (unlockResult != DD_OK)
  334. {
  335. //I have no idea how this could happen, but if it does, Just move on?
  336. // If the surface was not locked, something is really wrong.
  337. // We could LOSE the surface by switching focus but we lost the lock then anyway.
  338. }
  339. goto mouseTimerDone;
  340. }
  341. }
  342. }
  343. else
  344. {
  345. //ANY other situation means that for some reason the surface was unavailable.
  346. // We may have lost focus, GameOS is doing something stupid OR
  347. // some other unforseen event. Just don't update it.
  348. // We do not need to unlock. It was never locked.
  349. goto mouseTimerDone;
  350. }
  351. // Must now Unlock to the rect.
  352. // -Unlock Rect Cursor WAS in.
  353. unlockResult = FrontBufferSurface->Unlock(&mouseWASInRect);
  354. if (unlockResult != DD_OK)
  355. {
  356. //I have no idea how this could happen, but if it does, Just move on?
  357. // If the surface was not locked, something is really wrong.
  358. // We could LOSE the surface by switching focus but we lost the lock then anyway.
  359. }
  360. }
  361. //Check to see if we should even bother drawing the mouse. They may wanyt us OFF!!
  362. if (UserInput::drawMouse)
  363. {
  364. // -Get Current Mouse X and Y.
  365. // Copy code from GameOS here. DO NOT CALL GAMEOS FUNCTIONS!!!!!!
  366. // They are almost certainly not re-entrant!!
  367. //
  368. // Get absolute mouse position using window calls
  369. //
  370. POINT pt;
  371. GetCursorPos(&pt);
  372. //
  373. // Determine if cursor is out of WinRect. If so, clamp it back in.
  374. //
  375. if (pt.x < WinRect.left)
  376. {
  377. pt.x = WinRect.left;
  378. }
  379. else if (pt.x >= WinRect.right)
  380. {
  381. pt.x = WinRect.right;
  382. }
  383. if (pt.y < WinRect.top)
  384. {
  385. pt.y = WinRect.top;
  386. }
  387. else if (pt.y >= WinRect.bottom)
  388. {
  389. pt.y = WinRect.bottom;
  390. }
  391. //At this point, pt.x and pt.y contain the relative coords of the mouse in
  392. // OUR window space.
  393. if (!Environment.fullScreen)
  394. {
  395. screenX = WinRect.right;
  396. screenY = WinRect.bottom;
  397. }
  398. // -Lock Rect Cursor IS in.
  399. // In order to do this, you need the current mouse cursor hot spot.
  400. // the mouse HOTSPOT is at the pt coordinates. The rect is relative to that.
  401. mouseWASInRect.left = pt.x - mc2MouseHotSpotX;
  402. mouseWASInRect.top = pt.y - mc2MouseHotSpotY;
  403. mouseWASInRect.right = mouseWASInRect.left + mc2MouseWidth;
  404. mouseWASInRect.bottom = mouseWASInRect.top + mc2MouseHeight;
  405. if (mouseWASInRect.left >= (screenX-1))
  406. {
  407. mouseWASInRect.left = screenX-1;
  408. }
  409. if (mouseWASInRect.top >= (screenY-1))
  410. {
  411. mouseWASInRect.top = screenY-1;
  412. }
  413. if (mouseWASInRect.right >= (screenX-1))
  414. {
  415. mouseWASInRect.right = screenX-1;
  416. }
  417. if (mouseWASInRect.bottom >= (screenY-1))
  418. {
  419. mouseWASInRect.bottom = screenY-1;
  420. }
  421. //Lock can wait because the above unlock might not have been done baking yet!
  422. if (FrontBufferSurface)
  423. lockResult = FrontBufferSurface->Lock(NULL,&mouseSurfaceDesc,DDLOCK_WAIT,NULL);
  424. else
  425. lockResult = -1;
  426. if (lockResult == DD_OK)
  427. {
  428. //Good. Lock was OK.
  429. // -Copy Screen Contents of Rect to mouseBuffer.
  430. // Get the pixel Format and use it to copy data from the screen
  431. // to the mouseBuffer.
  432. //
  433. // Our new mouseRect may include negative numbers which are off screen.
  434. // Clip so that ALL numbers are greater then zero!!
  435. //
  436. if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 16)
  437. {
  438. MemoryPtr mBuffer = mouseBuffer;
  439. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  440. {
  441. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  442. ((mouseWASInRect.left << 1) +
  443. (y * mouseSurfaceDesc.lPitch));
  444. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  445. {
  446. //Only copy bytes that are on screen.
  447. if ((x > WinRect.left) && (y > WinRect.top))
  448. {
  449. //Copy first byte
  450. *mBuffer = *screenPos;
  451. mBuffer++;
  452. screenPos++;
  453. //Copy second byte
  454. *mBuffer = *screenPos;
  455. mBuffer++;
  456. screenPos++;
  457. }
  458. else
  459. {
  460. //Just iterate across the screen and buffer
  461. //
  462. //Skip first byte
  463. mBuffer++;
  464. screenPos++;
  465. //Skip second byte
  466. mBuffer++;
  467. screenPos++;
  468. }
  469. }
  470. }
  471. }
  472. else if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 24)
  473. {
  474. MemoryPtr mBuffer = mouseBuffer;
  475. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  476. {
  477. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  478. ((mouseWASInRect.left * 3) +
  479. (y * mouseSurfaceDesc.lPitch));
  480. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  481. {
  482. //Only copy bytes that are on screen.
  483. if ((x > WinRect.left) && (y > WinRect.top))
  484. {
  485. //Copy first byte
  486. *mBuffer = *screenPos;
  487. mBuffer++;
  488. screenPos++;
  489. //Copy second byte
  490. *mBuffer = *screenPos;
  491. mBuffer++;
  492. screenPos++;
  493. //Copy third byte
  494. *mBuffer = *screenPos;
  495. mBuffer++;
  496. screenPos++;
  497. }
  498. else
  499. {
  500. //Just iterate across the screen and buffer
  501. //
  502. //Skip first byte
  503. mBuffer++;
  504. screenPos++;
  505. //Skip second byte
  506. mBuffer++;
  507. screenPos++;
  508. //Skip third byte
  509. mBuffer++;
  510. screenPos++;
  511. }
  512. }
  513. }
  514. }
  515. else if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 32)
  516. {
  517. MemoryPtr mBuffer = mouseBuffer;
  518. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  519. {
  520. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  521. ((mouseWASInRect.left << 2) +
  522. (y * mouseSurfaceDesc.lPitch));
  523. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  524. {
  525. //Only copy bytes that are on screen.
  526. if ((x > WinRect.left) && (y > WinRect.top))
  527. {
  528. //Copy first byte
  529. *mBuffer = *screenPos;
  530. mBuffer++;
  531. screenPos++;
  532. //Copy second byte
  533. *mBuffer = *screenPos;
  534. mBuffer++;
  535. screenPos++;
  536. //Copy third byte
  537. *mBuffer = *screenPos;
  538. mBuffer++;
  539. screenPos++;
  540. //Copy fourth byte
  541. *mBuffer = *screenPos;
  542. mBuffer++;
  543. screenPos++;
  544. }
  545. else
  546. {
  547. //Just iterate across the screen and buffer
  548. //
  549. //Skip first byte
  550. mBuffer++;
  551. screenPos++;
  552. //Skip second byte
  553. mBuffer++;
  554. screenPos++;
  555. //Skip third byte
  556. mBuffer++;
  557. screenPos++;
  558. //Skip fourth byte
  559. mBuffer++;
  560. screenPos++;
  561. }
  562. }
  563. }
  564. }
  565. else
  566. {
  567. //We are in some WAY unknown video mode. Just get out.
  568. unlockResult = FrontBufferSurface->Unlock(&mouseWASInRect);
  569. if (unlockResult != DD_OK)
  570. {
  571. //I have no idea how this could happen, but if it does, Just move on?
  572. // If the surface was not locked, something is really wrong.
  573. // We could LOSE the surface by switching focus but we lost the lock then anyway.
  574. }
  575. goto mouseTimerDone;
  576. }
  577. // -BLT mouse cursor to Rect.
  578. // mc2MouseData should contain a 32-bit image of the mouse cursor.
  579. // BLT it to the mouseSurface.
  580. //
  581. // Again, the mouseRect may contain negative numbers.
  582. // This means do NOT BLT until numbers are greater then Zero
  583. // Keep iterating across the mouse shape, though!!
  584. if (mc2MouseData)
  585. {
  586. bool in555Mode = false;
  587. if (GetNumberOfBits(mouseSurfaceDesc.ddpfPixelFormat.dwGBitMask) == 5)
  588. in555Mode = true;
  589. if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 16)
  590. {
  591. DWORD * mData = (DWORD *)mc2MouseData;
  592. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  593. {
  594. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  595. ((mouseWASInRect.left << 1) +
  596. (y * mouseSurfaceDesc.lPitch));
  597. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  598. {
  599. //We are pointing at the top left corner of where
  600. // the mouse cursor will draw. mc2MouseData is a 32bit
  601. // bitmap with Alpha information. Go!
  602. DWORD mColor = *mData;
  603. BYTE baseAlpha = 0;
  604. BYTE baseColorRed = (mColor & 0x00ff0000)>>16;
  605. BYTE baseColorGreen = (mColor & 0x0000ff00)>>8;
  606. BYTE baseColorBlue = (mColor & 0x000000ff);
  607. //Check for color key instead
  608. if ((baseColorRed != 0xff) || (baseColorGreen != 0x0) || (baseColorBlue != 0xff))
  609. baseAlpha = 0x1;
  610. // Check if our rect is off screen and do not BLT!!
  611. if (baseAlpha && (x > WinRect.left) && (y > WinRect.top))
  612. {
  613. //Create a 16Bit color value to jam into the screen.
  614. unsigned short clr = 0;
  615. if (!in555Mode)
  616. {
  617. clr = (baseColorRed >> 3) << 11;
  618. clr += (baseColorGreen >> 2) << 5;
  619. clr += (baseColorBlue >> 3);
  620. }
  621. else
  622. {
  623. clr = (baseColorRed >> 3) << 10;
  624. clr += (baseColorGreen >> 3) << 5;
  625. clr += (baseColorBlue >> 3);
  626. }
  627. *screenPos = clr & 0xff;
  628. screenPos++;
  629. *screenPos = clr >> 8;
  630. screenPos++;
  631. }
  632. else
  633. {
  634. screenPos++;
  635. screenPos++;
  636. }
  637. //Always iterate across shape, even if not drawn
  638. mData++;
  639. }
  640. //Skip portion of mouse which is off bottom or right.
  641. mData += mc2MouseWidth - (mouseWASInRect.right - mouseWASInRect.left);
  642. }
  643. }
  644. else if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 24)
  645. {
  646. DWORD * mData = (DWORD *)mc2MouseData;
  647. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  648. {
  649. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  650. ((mouseWASInRect.left * 3) +
  651. (y * mouseSurfaceDesc.lPitch));
  652. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  653. {
  654. //We are pointing at the top left corner of where
  655. // the mouse cursor will draw. mc2MouseData is a 32bit
  656. // bitmap with Alpha information. Go!
  657. DWORD mColor = *mData;
  658. BYTE baseAlpha = 0;
  659. BYTE baseColorRed = (mColor & 0x00ff0000)>>16;
  660. BYTE baseColorGreen = (mColor & 0x0000ff00)>>8;
  661. BYTE baseColorBlue = (mColor & 0x000000ff);
  662. //Check for color key instead
  663. if ((baseColorRed != 0xff) || (baseColorGreen != 0x0) || (baseColorBlue != 0xff))
  664. baseAlpha = 0x1;
  665. // Check if our rect is off screen and do not BLT!!
  666. if (baseAlpha && (x > WinRect.left) && (y > WinRect.top))
  667. {
  668. //Just JAM colors into the screen
  669. // TRUE COLOR!!
  670. *screenPos = baseColorBlue;
  671. screenPos++;
  672. *screenPos = baseColorGreen;
  673. screenPos++;
  674. *screenPos = baseColorRed;
  675. screenPos++;
  676. }
  677. else
  678. {
  679. screenPos++;
  680. screenPos++;
  681. screenPos++;
  682. }
  683. //Always iterate across shape, even if not drawn
  684. mData++;
  685. }
  686. //Skip portion of mouse which is off bottom or right.
  687. mData += mc2MouseWidth - (mouseWASInRect.right - mouseWASInRect.left);
  688. }
  689. }
  690. else if (mouseSurfaceDesc.ddpfPixelFormat.dwRGBBitCount == 32)
  691. {
  692. DWORD * mData = (DWORD *)mc2MouseData;
  693. for (long y=mouseWASInRect.top;y<mouseWASInRect.bottom;y++)
  694. {
  695. MemoryPtr screenPos = (MemoryPtr)mouseSurfaceDesc.lpSurface +
  696. ((mouseWASInRect.left << 2) +
  697. (y * mouseSurfaceDesc.lPitch));
  698. for (long x=mouseWASInRect.left;x<mouseWASInRect.right;x++)
  699. {
  700. //We are pointing at the top left corner of where
  701. // the mouse cursor will draw. mc2MouseData is a 32bit
  702. // bitmap with Alpha information. Go!
  703. DWORD mColor = *mData;
  704. BYTE baseAlpha = 0;
  705. BYTE baseColorRed = (mColor & 0x00ff0000)>>16;
  706. BYTE baseColorGreen = (mColor & 0x0000ff00)>>8;
  707. BYTE baseColorBlue = (mColor & 0x000000ff);
  708. //Check for color key instead
  709. if ((baseColorRed != 0xff) || (baseColorGreen != 0x0) || (baseColorBlue != 0xff))
  710. baseAlpha = 0x1;
  711. // Check if our rect is off screen and do not BLT!!
  712. if (baseAlpha && (x > WinRect.left) && (y > WinRect.top))
  713. {
  714. //Just JAM colors into the screen
  715. // TRUE COLOR!!
  716. *screenPos = baseColorBlue;
  717. screenPos++;
  718. *screenPos = baseColorGreen;
  719. screenPos++;
  720. *screenPos = baseColorRed;
  721. screenPos++;
  722. screenPos++; //Jam one more for 32 Bits
  723. }
  724. else
  725. {
  726. screenPos++;
  727. screenPos++;
  728. screenPos++;
  729. screenPos++; //Jam one more for 32 Bits
  730. }
  731. //Always iterate across shape, even if not drawn
  732. mData++;
  733. }
  734. //Skip portion of mouse which is off bottom or right.
  735. mData += mc2MouseWidth - (mouseWASInRect.right - mouseWASInRect.left);
  736. }
  737. }
  738. }
  739. // -Unlock Rect Cursor IS in.
  740. unlockResult = FrontBufferSurface->Unlock(&mouseWASInRect);
  741. if (unlockResult != DD_OK)
  742. {
  743. //I have no idea how this could happen, but if it does, Just move on?
  744. // If the surface was not locked, something is really wrong.
  745. // We could LOSE the surface by switching focus but we lost the lock then anyway.
  746. }
  747. }
  748. else
  749. {
  750. //ANY other situation means that for some reason the surface was unavailable.
  751. // We may have lost focus, GameOS is doing something stupid OR
  752. // some other unforseen event. Just don't update it.
  753. // We do not need to unlock. It was never locked.
  754. goto mouseTimerDone;
  755. }
  756. }
  757. mouseTimerDone:
  758. //ALL done. It is now safe to allow DisplayBackBuffer to run.
  759. mc2IsInMouseTimer = false;
  760. mc2DisplayHasFlipped = false;
  761. }
  762. //-------------------------------------------------------------------