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

330 lines
9.7 KiB

  1. /****************************************************************************
  2. Glide.c
  3. June 91, JimH initial code
  4. Oct 91, JimH port to Win32
  5. Routines for gliding cards are here. There is only one public entry point
  6. to these routines, the function Glide().
  7. The glide speed can be altered by changing STEPSIZE. A large number (like
  8. 37) makes for fast glides.
  9. ****************************************************************************/
  10. #include "freecell.h"
  11. #include "freecons.h"
  12. #include <math.h> // for labs()
  13. #define STEPSIZE 37 // size of glide steps in pixels
  14. #define BGND 255 // used for cdtDrawExt
  15. static HDC hMemB1, hMemB2, hMemF; // mem DC associated with above bitmaps
  16. static HBITMAP hOB1, hOB2, hOF; // old bitmaps in above mem DCs
  17. static UINT dwPixel[12]; // corner pixels that are saved/restored
  18. static HRGN hRgn, hRgn1, hRgn2; // hRgn1 is source, hRgn2 is destination
  19. static VOID GlideInit(HWND hWnd, UINT fcol, UINT tcol);
  20. static INT IntSqrt(INT square);
  21. static VOID SaveCorners(HDC hDC, UINT x, UINT y);
  22. static VOID RestoreCorners(HDC hDC, UINT x, UINT y);
  23. /******************************************************************************
  24. Glide
  25. Given a from and to location, this function animates the movement of
  26. the card.
  27. ******************************************************************************/
  28. VOID Glide(HWND hWnd, UINT fcol, UINT fpos, UINT tcol, UINT tpos)
  29. {
  30. HDC hDC;
  31. INT dx, dy; // total distance card travels
  32. UINT x1, y1, x2, y2; // start and end locations for each step
  33. UINT xStart, yStart; // beginning position
  34. UINT xEnd =0, yEnd = 0; // destination position
  35. INT i;
  36. INT distance; // distance card travles +/- 3 pixels
  37. INT steps; // number of steps card takes in glide total
  38. BOOL bSaved = FALSE; // corner pixels saved?
  39. if (fcol != tcol || fpos != tpos) // if card moves
  40. {
  41. hDC = GetDC(hWnd);
  42. hMemB1 = CreateCompatibleDC(hDC); // memory DCs for bitmaps
  43. hMemB2 = CreateCompatibleDC(hDC);
  44. hMemF = CreateCompatibleDC(hDC);
  45. hRgn1 = CreateRectRgn(1, 1, 2, 2);
  46. hRgn2 = CreateRectRgn(1, 1, 2, 2);
  47. hRgn = CreateRectRgn(1, 1, 2, 2);
  48. if (hMemB1 && hMemB2 && hMemF && hRgn1 && hRgn2 && hRgn)
  49. {
  50. hOB1 = SelectObject(hMemB1, hBM_Bgnd1);
  51. hOB2 = SelectObject(hMemB2, hBM_Bgnd2);
  52. hOF = SelectObject(hMemF, hBM_Fgnd);
  53. GlideInit(hWnd, fcol, fpos); // set up hBM_Bgnd1 and hBM_Fgnd
  54. Card2Point(fcol, fpos, &xStart, &yStart);
  55. Card2Point(tcol, tpos, &xEnd, &yEnd);
  56. SaveCorners(hDC, xEnd, yEnd);
  57. bSaved = TRUE;
  58. /* Determine how far to travel and how many steps to take. */
  59. x1 = xStart;
  60. y1 = yStart;
  61. dx = xEnd - xStart;
  62. dy = yEnd - yStart;
  63. distance = IntSqrt(dx*dx + dy*dy);
  64. if (bFastMode)
  65. steps = 1;
  66. else
  67. steps = distance / STEPSIZE;
  68. /* Determine intermediate glide locations. Long arithmetic is
  69. needed to prevent overflows. */
  70. for (i = 1; i < steps; i++)
  71. {
  72. x2 = xStart + ((i * dx) / steps);
  73. y2 = yStart + ((i * dy) / steps);
  74. GlideStep(hDC, x1, y1, x2, y2);
  75. x1 = x2;
  76. y1 = y2;
  77. }
  78. /* Erase last background manually -- DrawCard will do last card. */
  79. BitBlt(hMemB1, xEnd-x1, yEnd-y1, dxCrd, dyCrd, hMemF,0,0,SRCCOPY);
  80. BitBlt(hDC, x1, y1, dxCrd, dyCrd, hMemB1, 0, 0, SRCCOPY);
  81. /* Select original bitmaps so mem DCs can be destroyed. */
  82. SelectObject(hMemB1, hOB1);
  83. SelectObject(hMemB2, hOB2);
  84. SelectObject(hMemF, hOF);
  85. }
  86. else
  87. {
  88. LoadString(hInst, IDS_MEMORY, bigbuf, BIG);
  89. LoadString(hInst, IDS_APPNAME, smallbuf, SMALL);
  90. MessageBeep(MB_ICONHAND);
  91. MessageBox(hWnd, bigbuf, smallbuf, MB_OK | MB_ICONHAND);
  92. moveindex = 0; // don't try moving more cards
  93. PostQuitMessage(0);
  94. }
  95. DeleteDC(hMemB1);
  96. DeleteDC(hMemB2);
  97. DeleteDC(hMemF);
  98. ReleaseDC(hWnd, hDC);
  99. DeleteObject(hRgn);
  100. DeleteObject(hRgn1);
  101. DeleteObject(hRgn2);
  102. }
  103. /* Draw last card with DrawCard so end result guaranteed correct. */
  104. hDC = GetDC(hWnd);
  105. DrawCard(hDC, tcol, tpos, card[fcol][fpos], FACEUP);
  106. if (bSaved)
  107. RestoreCorners(hDC, xEnd, yEnd);
  108. ReleaseDC(hWnd, hDC);
  109. }
  110. /******************************************************************************
  111. GlideInit
  112. Blt what is under the card source location into hMemB1, and the
  113. card to be moved into hMemF.
  114. ******************************************************************************/
  115. VOID GlideInit(HWND hWnd, UINT fcol, UINT fpos)
  116. {
  117. if (fcol == TOPROW) // if it's top row, background is ghost bitmap.
  118. {
  119. if (fpos > 3 && VALUE(card[fcol][fpos]) != ACE)
  120. {
  121. HDC hDC;
  122. UINT x, y;
  123. hDC = GetDC(hWnd);
  124. Card2Point(fcol, fpos, &x, &y);
  125. SaveCorners(hDC, x, y);
  126. cdtDrawExt(hMemB1,0,0,dxCrd,dyCrd,card[fcol][fpos]-4,FACEUP,BGND);
  127. RestoreCorners(hMemB1, 0, 0);
  128. ReleaseDC(hWnd, hDC);
  129. }
  130. else
  131. {
  132. SelectObject(hMemB2, hBM_Ghost);
  133. BitBlt(hMemB1, 0, 0, dxCrd, dyCrd, hMemB2, 0, 0, SRCCOPY);
  134. SelectObject(hMemB2, hBM_Bgnd2);
  135. }
  136. }
  137. else // else background contains bottom part of card above.
  138. {
  139. SelectObject(hMemB1, hBgndBrush);
  140. PatBlt(hMemB1, 0, 0, dxCrd, dyCrd, PATCOPY);
  141. if (fpos != 0)
  142. {
  143. cdtDrawExt(hMemB1, 0, 0-dyTops, dxCrd, dyCrd, card[fcol][fpos-1],
  144. FACEUP, BGND);
  145. }
  146. }
  147. /* Foreground bitmap is just the card to be moved. */
  148. cdtDrawExt(hMemF, 0, 0, dxCrd, dyCrd, card[fcol][fpos], FACEUP, 0);
  149. }
  150. /******************************************************************************
  151. GlideStep
  152. This routine gets called once for each step in the glide animation. On
  153. input, it needs the screen under the source in hMemB1, and the card to be
  154. moved in hMemF. It calculates the screen under the destination itself and
  155. blts it into hMemB2. At the end of the animation, it moves hMemB2 into
  156. hMemB1 so it can be call again immediately with new coordinates.
  157. ******************************************************************************/
  158. VOID GlideStep(HDC hDC, UINT x1, UINT y1, UINT x2, UINT y2)
  159. {
  160. HDC hMemTemp; // used to swap mem DCs.
  161. SetRectRgn(hRgn1, x1, y1, x1+dxCrd, y1+dyCrd);
  162. SetRectRgn(hRgn2, x2, y2, x2+dxCrd, y2+dyCrd);
  163. /* create background of new location by combing screen background
  164. plus overlap from old background */
  165. BitBlt(hMemB2, 0, 0, dxCrd, dyCrd, hDC, x2, y2, SRCCOPY);
  166. BitBlt(hMemB2, x1-x2, y1-y2, dxCrd, dyCrd, hMemB1, 0, 0, SRCCOPY);
  167. /* Draw old background and then draw card */
  168. CombineRgn(hRgn, hRgn1, hRgn2, RGN_DIFF); // part of hRgn1 not in hRgn2
  169. SelectObject(hDC, hRgn);
  170. BitBlt(hDC, x1, y1, dxCrd, dyCrd, hMemB1, 0, 0, SRCCOPY);
  171. SelectObject(hDC, hRgn2);
  172. BitBlt(hDC, x2, y2, dxCrd, dyCrd, hMemF, 0, 0, SRCCOPY);
  173. /* copy new background to old background, or rather, accomplish the
  174. same effect by swapping the associated memory device contexts. */
  175. hMemTemp = hMemB1;
  176. hMemB1 = hMemB2;
  177. hMemB2 = hMemTemp;
  178. }
  179. /******************************************************************************
  180. IntSqrt
  181. Newton's method to find a quick close-enough square root without pulling
  182. in the floating point libraries.
  183. f(x) == x*x - square == 0
  184. f'(x) == 2x
  185. ******************************************************************************/
  186. INT IntSqrt(INT square)
  187. {
  188. INT guess, lastguess;
  189. lastguess = square;
  190. guess = min(square / 2, 1024);
  191. while (abs(guess-lastguess) > 3) // 3 is close enough
  192. {
  193. lastguess = guess;
  194. guess -= ((guess * guess) - square) / (2 * guess);
  195. }
  196. return guess;
  197. }
  198. /******************************************************************************
  199. SaveCorners
  200. RestoreCorners
  201. based on similar routines in cards.dll
  202. ******************************************************************************/
  203. VOID SaveCorners(HDC hDC, UINT x, UINT y)
  204. {
  205. // Upper Left
  206. dwPixel[0] = GetPixel(hDC, x, y);
  207. dwPixel[1] = GetPixel(hDC, x+1, y);
  208. dwPixel[2] = GetPixel(hDC, x, y+1);
  209. // Upper Right
  210. x += dxCrd -1;
  211. dwPixel[3] = GetPixel(hDC, x, y);
  212. dwPixel[4] = GetPixel(hDC, x-1, y);
  213. dwPixel[5] = GetPixel(hDC, x, y+1);
  214. // Lower Right
  215. y += dyCrd-1;
  216. dwPixel[6] = GetPixel(hDC, x, y);
  217. dwPixel[7] = GetPixel(hDC, x, y-1);
  218. dwPixel[8] = GetPixel(hDC, x-1, y);
  219. // Lower Left
  220. x -= dxCrd-1;
  221. dwPixel[9] = GetPixel(hDC, x, y);
  222. dwPixel[10] = GetPixel(hDC, x+1, y);
  223. dwPixel[11] = GetPixel(hDC, x, y-1);
  224. }
  225. VOID RestoreCorners(HDC hDC, UINT x, UINT y)
  226. {
  227. // Upper Left
  228. SetPixel(hDC, x, y, dwPixel[0]);
  229. SetPixel(hDC, x+1, y, dwPixel[1]);
  230. SetPixel(hDC, x, y+1, dwPixel[2]);
  231. // Upper Right
  232. x += dxCrd-1;
  233. SetPixel(hDC, x, y, dwPixel[3]);
  234. SetPixel(hDC, x-1, y, dwPixel[4]);
  235. SetPixel(hDC, x, y+1, dwPixel[5]);
  236. // Lower Right
  237. y += dyCrd-1;
  238. SetPixel(hDC, x, y, dwPixel[6]);
  239. SetPixel(hDC, x, y-1, dwPixel[7]);
  240. SetPixel(hDC, x-1, y, dwPixel[8]);
  241. // Lower Left
  242. x -= dxCrd-1;
  243. SetPixel(hDC, x, y, dwPixel[9]);
  244. SetPixel(hDC, x+1, y, dwPixel[10]);
  245. SetPixel(hDC, x, y-1, dwPixel[11]);
  246. }