textures_cellular_automata.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*******************************************************************************************
  2. *
  3. * raylib [textures] example - cellular automata
  4. *
  5. * Example complexity rating: [★★☆☆] 2/4
  6. *
  7. * Example originally created with raylib 5.6, last time updated with raylib 5.6
  8. *
  9. * Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
  10. *
  11. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  12. * BSD-like license that allows static linking with closed source software
  13. *
  14. * Copyright (c) 2025 Jordi Santonja (@JordSant)
  15. *
  16. ********************************************************************************************/
  17. #include "raylib.h"
  18. // Initialization constants
  19. //--------------------------------------------------------------------------------------
  20. const int screenWidth = 800;
  21. const int screenHeight = 450;
  22. const int imageWidth = 800;
  23. const int imageHeight = 800/2;
  24. // Rule button sizes and positions
  25. const int drawRuleStartX = 585;
  26. const int drawRuleStartY = 10;
  27. const int drawRuleSpacing = 15;
  28. const int drawRuleGroupSpacing = 50;
  29. const int drawRuleSize = 14;
  30. const int drawRuleInnerSize = 10;
  31. // Preset button sizes
  32. const int presetsSizeX = 42;
  33. const int presetsSizeY = 22;
  34. const int linesUpdatedPerFrame = 4;
  35. //----------------------------------------------------------------------------------
  36. // Functions
  37. //----------------------------------------------------------------------------------
  38. void ComputeLine(Image *image, int line, int rule)
  39. {
  40. // Compute next line pixels. Boundaries are not computed, always 0
  41. for (int i = 1; i < imageWidth - 1; i++)
  42. {
  43. // Get, from the previous line, the 3 pixels states as a binary value
  44. const int prevValue = ((GetImageColor(*image, i - 1, line - 1).r < 5)? 4 : 0) + // Left pixel
  45. ((GetImageColor(*image, i, line - 1).r < 5)? 2 : 0) + // Center pixel
  46. ((GetImageColor(*image, i + 1, line - 1).r < 5)? 1 : 0); // Right pixel
  47. // Get next value from rule bitmask
  48. const bool currValue = (rule & (1 << prevValue));
  49. // Update pixel color
  50. ImageDrawPixel(image, i, line, (currValue)? BLACK : RAYWHITE);
  51. }
  52. }
  53. //------------------------------------------------------------------------------------
  54. // Program main entry point
  55. //------------------------------------------------------------------------------------
  56. int main(void)
  57. {
  58. // Initialization
  59. //--------------------------------------------------------------------------------------
  60. InitWindow(screenWidth, screenHeight, "raylib [textures] example - cellular automata");
  61. // Image that contains the cellular automaton
  62. Image image = GenImageColor(imageWidth, imageHeight, RAYWHITE);
  63. // The top central pixel set as black
  64. ImageDrawPixel(&image, imageWidth/2, 0, BLACK);
  65. Texture2D texture = LoadTextureFromImage(image);
  66. // Some interesting rules
  67. const int presetValues[] = { 18, 30, 60, 86, 102, 124, 126, 150, 182, 225 };
  68. const int presetsCount = sizeof(presetValues)/sizeof(presetValues[0]);
  69. // Variables
  70. int rule = 30; // Starting rule
  71. int line = 1; // Line to compute, starting from line 1. One point in line 0 is already set
  72. SetTargetFPS(60);
  73. //---------------------------------------------------------------------------------------
  74. // Main game loop
  75. while (!WindowShouldClose()) // Detect window close button or ESC key
  76. {
  77. // Update
  78. //----------------------------------------------------------------------------------
  79. // Handle mouse
  80. const Vector2 mouse = GetMousePosition();
  81. int mouseInCell = -1; // -1: outside any button; 0-7: rule cells; 8+: preset cells
  82. // Check mouse on rule cells
  83. for (int i = 0; i < 8; i++)
  84. {
  85. const int cellX = drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing;
  86. const int cellY = drawRuleStartY + drawRuleSpacing;
  87. if ((mouse.x >= cellX) && (mouse.x <= cellX + drawRuleSize) &&
  88. (mouse.y >= cellY) && (mouse.y <= cellY + drawRuleSize))
  89. {
  90. mouseInCell = i; // 0-7: rule cells
  91. break;
  92. }
  93. }
  94. // Check mouse on preset cells
  95. if (mouseInCell < 0)
  96. {
  97. for (int i = 0; i < presetsCount; i++)
  98. {
  99. const int cellX = 4 + (presetsSizeX + 2)*(i/2);
  100. const int cellY = 2 + (presetsSizeY + 2)*(i%2);
  101. if ((mouse.x >= cellX) && (mouse.x <= cellX + presetsSizeX) &&
  102. (mouse.y >= cellY) && (mouse.y <= cellY + presetsSizeY))
  103. {
  104. mouseInCell = i + 8; // 8+: preset cells
  105. break;
  106. }
  107. }
  108. }
  109. if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (mouseInCell >= 0))
  110. {
  111. // Rule changed both by selecting a preset or toggling a bit
  112. if (mouseInCell < 8)
  113. rule ^= (1 << mouseInCell);
  114. else
  115. rule = presetValues[mouseInCell - 8];
  116. // Reset image
  117. ImageClearBackground(&image, RAYWHITE);
  118. ImageDrawPixel(&image, imageWidth/2, 0, BLACK);
  119. line = 1;
  120. }
  121. // Compute next lines
  122. //----------------------------------------------------------------------------------
  123. if (line < imageHeight)
  124. {
  125. for (int i = 0; (i < linesUpdatedPerFrame) && (line + i < imageHeight); i++)
  126. ComputeLine(&image, line + i, rule);
  127. line += linesUpdatedPerFrame;
  128. UpdateTexture(texture, image.data);
  129. }
  130. //----------------------------------------------------------------------------------
  131. // Draw
  132. //----------------------------------------------------------------------------------
  133. BeginDrawing();
  134. ClearBackground(RAYWHITE);
  135. // Draw cellular automaton texture
  136. DrawTexture(texture, 0, screenHeight - imageHeight, WHITE);
  137. // Draw preset values
  138. for (int i = 0; i < presetsCount; i++)
  139. {
  140. DrawText(TextFormat("%i", presetValues[i]), 8 + (presetsSizeX + 2)*(i/2), 4 + (presetsSizeY + 2)*(i%2), 20, GRAY);
  141. DrawRectangleLines(4 + (presetsSizeX + 2)*(i/2), 2 + (presetsSizeY + 2)*(i%2), presetsSizeX, presetsSizeY, BLUE);
  142. // If the mouse is on this preset, highlight it
  143. if (mouseInCell == i + 8)
  144. DrawRectangleLinesEx((Rectangle) { 2 + (presetsSizeX + 2.0f)*(i/2),
  145. (presetsSizeY + 2.0f)*(i%2),
  146. presetsSizeX + 4.0f, presetsSizeY + 4.0f }, 3, RED);
  147. }
  148. // Draw rule bits
  149. for (int i = 0; i < 8; i++)
  150. {
  151. // The three input bits
  152. for (int j = 0; j < 3; j++)
  153. {
  154. DrawRectangleLines(drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing*j, drawRuleStartY, drawRuleSize, drawRuleSize, GRAY);
  155. if (i & (4 >> j))
  156. DrawRectangle(drawRuleStartX + 2 - drawRuleGroupSpacing*i + drawRuleSpacing*j, drawRuleStartY + 2, drawRuleInnerSize, drawRuleInnerSize, BLACK);
  157. }
  158. // The output bit
  159. DrawRectangleLines(drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing, drawRuleStartY + drawRuleSpacing, drawRuleSize, drawRuleSize, BLUE);
  160. if (rule & (1 << i))
  161. DrawRectangle(drawRuleStartX + 2 - drawRuleGroupSpacing*i + drawRuleSpacing, drawRuleStartY + 2 + drawRuleSpacing, drawRuleInnerSize, drawRuleInnerSize, BLACK);
  162. // If the mouse is on this rule bit, highlight it
  163. if (mouseInCell == i)
  164. DrawRectangleLinesEx((Rectangle){ drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing - 2.0f,
  165. drawRuleStartY + drawRuleSpacing - 2.0f,
  166. drawRuleSize + 4.0f, drawRuleSize + 4.0f }, 3, RED);
  167. }
  168. DrawText(TextFormat("RULE: %i", rule), drawRuleStartX + drawRuleSpacing*4, drawRuleStartY + 1, 30, GRAY);
  169. EndDrawing();
  170. //----------------------------------------------------------------------------------
  171. }
  172. // De-Initialization
  173. //--------------------------------------------------------------------------------------
  174. UnloadImage(image);
  175. UnloadTexture(texture);
  176. CloseWindow(); // Close window and OpenGL context
  177. //--------------------------------------------------------------------------------------
  178. return 0;
  179. }