Bunch of screensavers in Windows
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.

282 lines
8.5 KiB

  1. using Microsoft.Win32;
  2. using System;
  3. using System.Drawing;
  4. using System.Runtime.InteropServices;
  5. using System.Windows.Forms;
  6. using unvell.D2DLib;
  7. using unvell.D2DLib.WinForm;
  8. namespace GameOfLife
  9. {
  10. public partial class MainForm : D2DForm
  11. {
  12. private Point mouseLocation;
  13. private bool[,] newCells;
  14. private bool[,] oldCells;
  15. private Random random;
  16. private int gridSize = 8;
  17. private int magicCells = 0;
  18. private double density = 0.5;
  19. private int interval = 100;
  20. // TODO color
  21. //private int color;
  22. private D2DRect boundsRect;
  23. private D2DRect cellRect;
  24. private int maxX;
  25. private int maxY;
  26. private int firstX;
  27. private int lastX;
  28. private int firstY;
  29. private int lastY;
  30. private bool previewMode;
  31. [DllImport("user32.dll")]
  32. static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
  33. [DllImport("user32.dll")]
  34. static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
  35. [DllImport("user32.dll", SetLastError = true)]
  36. static extern int GetWindowLong(IntPtr hWnd, int nIndex);
  37. [DllImport("user32.dll")]
  38. static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);
  39. private void LoadSettings()
  40. {
  41. RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\TheoryOfNekomata\\WindowsScreensavers\\GameOfLife");
  42. var retrievedGridSize = 3;
  43. var retrievedSpores = 0;
  44. int retrievedDensity = 50;
  45. var retrievedInterval = 250;
  46. var gridSizes = new int[] { 1, 2, 4, 8 };
  47. if (key != null)
  48. {
  49. retrievedGridSize = (int)key.GetValue("GridSizeIndex", 3);
  50. retrievedSpores = (int)key.GetValue("Spores", 0);
  51. retrievedDensity = (int)key.GetValue("DensityPercentage", 50);
  52. retrievedInterval = (int)key.GetValue("IntervalMs", 250);
  53. }
  54. gridSize = gridSizes[retrievedGridSize];
  55. magicCells = retrievedSpores;
  56. density = ((double)retrievedDensity) / 100.0;
  57. interval = retrievedInterval;
  58. }
  59. private void SetBounds(Rectangle bounds) {
  60. Bounds = bounds;
  61. boundsRect = new D2DRect(Bounds.Left, Bounds.Top, Bounds.Width, Bounds.Height);
  62. }
  63. private void RandomizeCells() {
  64. random = new Random();
  65. maxX = Bounds.Width / gridSize;
  66. maxY = Bounds.Height / gridSize;
  67. newCells = new bool[maxX, maxY];
  68. oldCells = new bool[maxX, maxY];
  69. firstX = oldCells.GetLowerBound(0);
  70. lastX = oldCells.GetUpperBound(0);
  71. firstY = oldCells.GetLowerBound(1);
  72. lastY = oldCells.GetUpperBound(1);
  73. for (var x = 0; x < maxX; x++)
  74. {
  75. for (var y = 0; y < maxY; y++)
  76. {
  77. newCells[x, y] = random.NextDouble() <= density;
  78. oldCells[x, y] = false;
  79. }
  80. }
  81. }
  82. public MainForm(Rectangle bounds)
  83. {
  84. LoadSettings();
  85. InitializeComponent();
  86. SetBounds(bounds);
  87. RandomizeCells();
  88. }
  89. public MainForm(IntPtr PreviewWndHandle)
  90. {
  91. LoadSettings();
  92. gridSize = 1;
  93. magicCells = 0;
  94. density = 0.5;
  95. InitializeComponent();
  96. // Set the preview window as the parent of this window
  97. SetParent(this.Handle, PreviewWndHandle);
  98. // Make this a child window so it will close when the parent dialog closes
  99. // GWL_STYLE = -16, WS_CHILD = 0x40000000
  100. SetWindowLong(this.Handle, -16, new IntPtr(GetWindowLong(this.Handle, -16) | 0x40000000));
  101. // Place our window inside the parent
  102. Rectangle ParentRect;
  103. GetClientRect(PreviewWndHandle, out ParentRect);
  104. Size = ParentRect.Size;
  105. Location = new Point(0, 0);
  106. RandomizeCells();
  107. previewMode = true;
  108. }
  109. private void MainForm_Load(object sender, EventArgs e)
  110. {
  111. Cursor.Hide();
  112. TopMost = true;
  113. timer.Interval = interval;
  114. timer.Tick += new EventHandler(timer_Tick);
  115. timer.Start();
  116. }
  117. private void MainForm_MouseMove(object sender, MouseEventArgs e)
  118. {
  119. if (!previewMode)
  120. {
  121. if (!mouseLocation.IsEmpty)
  122. {
  123. // Terminate if mouse is moved a significant distance
  124. if (Math.Abs(mouseLocation.X - e.X) > 5 ||
  125. Math.Abs(mouseLocation.Y - e.Y) > 5)
  126. Application.Exit();
  127. }
  128. // Update current mouse location
  129. mouseLocation = e.Location;
  130. }
  131. }
  132. private void MainForm_MouseClick(object sender, MouseEventArgs e)
  133. {
  134. if (!previewMode)
  135. {
  136. Application.Exit();
  137. }
  138. }
  139. private void MainForm_KeyPress(object sender, KeyPressEventArgs e)
  140. {
  141. if (!previewMode)
  142. {
  143. Application.Exit();
  144. }
  145. }
  146. private int GetAliveNeighbors(int x, int y) {
  147. int prevX = x == firstX ? lastX : x - 1;
  148. int nextX = x == lastX ? firstX : x + 1;
  149. int prevY = y == firstY ? lastY : y - 1;
  150. int nextY = y == lastY ? firstY : y + 1;
  151. int aliveNeighbors = 0;
  152. if (oldCells[prevX, prevY]) {
  153. aliveNeighbors += 1;
  154. }
  155. if (oldCells[x, prevY])
  156. {
  157. aliveNeighbors += 1;
  158. }
  159. if (oldCells[nextX, prevY])
  160. {
  161. aliveNeighbors += 1;
  162. }
  163. if (oldCells[prevX, y])
  164. {
  165. aliveNeighbors += 1;
  166. }
  167. if (oldCells[nextX, y])
  168. {
  169. aliveNeighbors += 1;
  170. }
  171. if (oldCells[prevX, nextY])
  172. {
  173. aliveNeighbors += 1;
  174. }
  175. if (oldCells[x, nextY])
  176. {
  177. aliveNeighbors += 1;
  178. }
  179. if (oldCells[nextX, nextY])
  180. {
  181. aliveNeighbors += 1;
  182. }
  183. return aliveNeighbors;
  184. }
  185. private void timer_Tick(object sender, EventArgs e) {
  186. for (var x = 0; x < newCells.GetLength(0); x++)
  187. {
  188. for (var y = 0; y < newCells.GetLength(1); y++)
  189. {
  190. oldCells[x, y] = newCells[x, y];
  191. }
  192. }
  193. for (var x = 0; x < newCells.GetLength(0); x++)
  194. {
  195. for (var y = 0; y < newCells.GetLength(1); y++)
  196. {
  197. int neighbors = GetAliveNeighbors(x, y);
  198. bool shouldLive = false;
  199. if (oldCells[x, y] && neighbors == 2)
  200. {
  201. shouldLive = true;
  202. } else if (!oldCells[x, y] && neighbors == 3) {
  203. shouldLive = true;
  204. }
  205. newCells[x, y] = shouldLive;
  206. }
  207. }
  208. for (var i = 0; i < magicCells; i++) {
  209. int magicX = random.Next(0, newCells.GetUpperBound(0));
  210. int magicY = random.Next(0, newCells.GetUpperBound(1));
  211. newCells[magicX, magicY] = true;
  212. }
  213. Refresh();
  214. }
  215. protected override void OnRender(D2DGraphics graphics)
  216. {
  217. graphics.FillRectangle(boundsRect, D2DColor.White);
  218. for (var x = 0; x < newCells.GetLength(0); x++)
  219. {
  220. for (var y = 0; y < newCells.GetLength(1); y++)
  221. {
  222. if (!newCells[x, y])
  223. {
  224. cellRect = new D2DRect(x * gridSize, y * gridSize, gridSize, gridSize);
  225. graphics.FillRectangle(cellRect, D2DColor.Black);
  226. }
  227. }
  228. }
  229. }
  230. }
  231. }