Skip to content

Commit efeccfe

Browse files
authored
[examples] Add textures_cellular_automata (#5395)
* [examples] Add `textures_cellular_automata` * Comparison always true. Fixed * Tabs to spaces
1 parent 366300a commit efeccfe

File tree

3 files changed

+781
-0
lines changed

3 files changed

+781
-0
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*******************************************************************************************
2+
*
3+
* raylib [textures] example - one-dimensional elementary 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+
18+
#include "raylib.h"
19+
20+
// Initialization constants
21+
//--------------------------------------------------------------------------------------
22+
const int screenWidth = 800;
23+
const int screenHeight = 450;
24+
const int imageWidth = 800;
25+
const int imageHeight = 800/2;
26+
27+
// Rule button sizes and positions
28+
const int drawRuleStartX = 585;
29+
const int drawRuleStartY = 10;
30+
const int drawRuleSpacing = 15;
31+
const int drawRuleGroupSpacing = 50;
32+
const int drawRuleSize = 14;
33+
const int drawRuleInnerSize = 10;
34+
35+
// Preset button sizes
36+
const int presetsSizeX = 42;
37+
const int presetsSizeY = 22;
38+
39+
const int linesUpdatedPerFrame = 4;
40+
41+
//----------------------------------------------------------------------------------
42+
// Functions
43+
//----------------------------------------------------------------------------------
44+
void ComputeLine(Image *image, int line, int rule)
45+
{
46+
// Compute next line pixels. Boundaries are not computed, always 0
47+
for (int i = 1; i < imageWidth - 1; i++)
48+
{
49+
// Get, from the previous line, the 3 pixels states as a binary value
50+
const int prevValue = ((GetImageColor(*image, i - 1, line - 1).r < 5)? 4 : 0) + // Left pixel
51+
((GetImageColor(*image, i, line - 1).r < 5)? 2 : 0) + // Center pixel
52+
((GetImageColor(*image, i + 1, line - 1).r < 5)? 1 : 0); // Right pixel
53+
// Get next value from rule bitmask
54+
const bool currValue = (rule & (1 << prevValue));
55+
// Update pixel color
56+
ImageDrawPixel(image, i, line, (currValue)? BLACK : RAYWHITE);
57+
}
58+
}
59+
60+
//------------------------------------------------------------------------------------
61+
// Program main entry point
62+
//------------------------------------------------------------------------------------
63+
int main(void)
64+
{
65+
// Initialization
66+
//--------------------------------------------------------------------------------------
67+
InitWindow(screenWidth, screenHeight, "raylib [textures] example - elementary cellular automata");
68+
69+
// Image that contains the cellular automaton
70+
Image image = GenImageColor(imageWidth, imageHeight, RAYWHITE);
71+
// The top central pixel set as black
72+
ImageDrawPixel(&image, imageWidth/2, 0, BLACK);
73+
74+
Texture2D texture = LoadTextureFromImage(image);
75+
76+
// Some interesting rules
77+
const int presetValues[] = { 18, 30, 60, 86, 102, 124, 126, 150, 182, 225 };
78+
const int presetsCount = sizeof(presetValues)/sizeof(presetValues[0]);
79+
80+
// Variables
81+
int rule = 30; // Starting rule
82+
int line = 1; // Line to compute, starting from line 1. One point in line 0 is already set
83+
84+
SetTargetFPS(60);
85+
//---------------------------------------------------------------------------------------
86+
87+
// Main game loop
88+
while (!WindowShouldClose()) // Detect window close button or ESC key
89+
{
90+
// Update
91+
//----------------------------------------------------------------------------------
92+
// Handle mouse
93+
const Vector2 mouse = GetMousePosition();
94+
int mouseInCell = -1; // -1: outside any button; 0-7: rule cells; 8+: preset cells
95+
96+
// Check mouse on rule cells
97+
for (int i = 0; i < 8; i++)
98+
{
99+
const int cellX = drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing;
100+
const int cellY = drawRuleStartY + drawRuleSpacing;
101+
if ((mouse.x >= cellX) && (mouse.x <= cellX + drawRuleSize) &&
102+
(mouse.y >= cellY) && (mouse.y <= cellY + drawRuleSize))
103+
{
104+
mouseInCell = i; // 0-7: rule cells
105+
break;
106+
}
107+
}
108+
109+
// Check mouse on preset cells
110+
if (mouseInCell < 0)
111+
{
112+
for (int i = 0; i < presetsCount; i++)
113+
{
114+
const int cellX = 4 + (presetsSizeX + 2)*(i/2);
115+
const int cellY = 2 + (presetsSizeY + 2)*(i%2);
116+
if ((mouse.x >= cellX) && (mouse.x <= cellX + presetsSizeX) &&
117+
(mouse.y >= cellY) && (mouse.y <= cellY + presetsSizeY))
118+
{
119+
mouseInCell = i + 8; // 8+: preset cells
120+
break;
121+
}
122+
}
123+
}
124+
125+
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (mouseInCell >= 0))
126+
{
127+
// Rule changed both by selecting a preset or toggling a bit
128+
if (mouseInCell < 8)
129+
rule ^= (1 << mouseInCell);
130+
else
131+
rule = presetValues[mouseInCell - 8];
132+
133+
// Reset image
134+
ImageClearBackground(&image, RAYWHITE);
135+
ImageDrawPixel(&image, imageWidth/2, 0, BLACK);
136+
line = 1;
137+
}
138+
139+
// Compute next lines
140+
//----------------------------------------------------------------------------------
141+
if (line < imageHeight)
142+
{
143+
for (int i = 0; (i < linesUpdatedPerFrame) && (line + i < imageHeight); i++)
144+
ComputeLine(&image, line + i, rule);
145+
line += linesUpdatedPerFrame;
146+
147+
UpdateTexture(texture, image.data);
148+
}
149+
150+
//----------------------------------------------------------------------------------
151+
152+
// Draw
153+
//----------------------------------------------------------------------------------
154+
BeginDrawing();
155+
ClearBackground(RAYWHITE);
156+
157+
// Draw cellular automaton texture
158+
DrawTexture(texture, 0, screenHeight - imageHeight, WHITE);
159+
160+
// Draw preset values
161+
for (int i = 0; i < presetsCount; i++)
162+
{
163+
DrawText(TextFormat("%i", presetValues[i]), 8 + (presetsSizeX + 2)*(i/2), 4 + (presetsSizeY + 2)*(i%2), 20, GRAY);
164+
DrawRectangleLines(4 + (presetsSizeX + 2)*(i/2), 2 + (presetsSizeY + 2)*(i%2), presetsSizeX, presetsSizeY, BLUE);
165+
166+
// If the mouse is on this preset, highlight it
167+
if (mouseInCell == i + 8)
168+
DrawRectangleLinesEx((Rectangle) { 2 + (presetsSizeX + 2.0f)*(i/2),
169+
(presetsSizeY + 2.0f)*(i%2),
170+
presetsSizeX + 4.0f, presetsSizeY + 4.0f }, 3, RED);
171+
}
172+
173+
// Draw rule bits
174+
for (int i = 0; i < 8; i++)
175+
{
176+
// The three input bits
177+
for (int j = 0; j < 3; j++)
178+
{
179+
DrawRectangleLines(drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing*j, drawRuleStartY, drawRuleSize, drawRuleSize, GRAY);
180+
if (i & (4 >> j))
181+
DrawRectangle(drawRuleStartX + 2 - drawRuleGroupSpacing*i + drawRuleSpacing*j, drawRuleStartY + 2, drawRuleInnerSize, drawRuleInnerSize, BLACK);
182+
}
183+
184+
// The output bit
185+
DrawRectangleLines(drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing, drawRuleStartY + drawRuleSpacing, drawRuleSize, drawRuleSize, BLUE);
186+
if (rule & (1 << i))
187+
DrawRectangle(drawRuleStartX + 2 - drawRuleGroupSpacing*i + drawRuleSpacing, drawRuleStartY + 2 + drawRuleSpacing, drawRuleInnerSize, drawRuleInnerSize, BLACK);
188+
189+
// If the mouse is on this rule bit, highlight it
190+
if (mouseInCell == i)
191+
DrawRectangleLinesEx((Rectangle){ drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing - 2.0f,
192+
drawRuleStartY + drawRuleSpacing - 2.0f,
193+
drawRuleSize + 4.0f, drawRuleSize + 4.0f }, 3, RED);
194+
}
195+
196+
DrawText(TextFormat("RULE: %i", rule), drawRuleStartX + drawRuleSpacing*4, drawRuleStartY + 1, 30, GRAY);
197+
198+
EndDrawing();
199+
//----------------------------------------------------------------------------------
200+
}
201+
202+
// De-Initialization
203+
//--------------------------------------------------------------------------------------
204+
UnloadImage(image);
205+
UnloadTexture(texture);
206+
207+
CloseWindow(); // Close window and OpenGL context
208+
//--------------------------------------------------------------------------------------
209+
210+
return 0;
211+
}
212+
14.5 KB
Loading

0 commit comments

Comments
 (0)