merge: Go mechanics
This commit is contained in:
@@ -60,11 +60,14 @@ int config_parse_mods(const char *s, uint32_t *out_mods, char **out_key) {
|
|||||||
while (t) {
|
while (t) {
|
||||||
char *tt = trim(t);
|
char *tt = trim(t);
|
||||||
if (*tt) {
|
if (*tt) {
|
||||||
|
char *alias = tt;
|
||||||
|
if (strcmp(tt, "+") == 0) alias = "plus";
|
||||||
|
else if (strcmp(tt, "-") == 0) alias = "minus";
|
||||||
if (n == cap) {
|
if (n == cap) {
|
||||||
cap = cap ? cap * 2 : 4;
|
cap = cap ? cap * 2 : 4;
|
||||||
toks = realloc(toks, cap * sizeof(char *));
|
toks = realloc(toks, cap * sizeof(char *));
|
||||||
}
|
}
|
||||||
toks[n++] = strdup(tt);
|
toks[n++] = strdup(alias);
|
||||||
}
|
}
|
||||||
t = strtok_r(NULL, "+", &save);
|
t = strtok_r(NULL, "+", &save);
|
||||||
}
|
}
|
||||||
@@ -129,6 +132,10 @@ config_t config_defaults(void) {
|
|||||||
{"space", ACTION_ROTATE},
|
{"space", ACTION_ROTATE},
|
||||||
{"escape", ACTION_CANCEL},
|
{"escape", ACTION_CANCEL},
|
||||||
{"ctrl+q", ACTION_QUIT},
|
{"ctrl+q", ACTION_QUIT},
|
||||||
|
{"p", ACTION_PAUSE},
|
||||||
|
{"n", ACTION_STEP},
|
||||||
|
{"+", ACTION_SPEED_UP},
|
||||||
|
{"-", ACTION_SPEED_DOWN},
|
||||||
};
|
};
|
||||||
int ndef = sizeof(defs) / sizeof(defs[0]);
|
int ndef = sizeof(defs) / sizeof(defs[0]);
|
||||||
for (int i = 0; i < ndef; i++) {
|
for (int i = 0; i < ndef; i++) {
|
||||||
@@ -152,7 +159,11 @@ static const char *default_file_content =
|
|||||||
"\"4\" = \"select:toad\"\n"
|
"\"4\" = \"select:toad\"\n"
|
||||||
"\"space\" = \"rotate\"\n"
|
"\"space\" = \"rotate\"\n"
|
||||||
"\"escape\" = \"cancel\"\n"
|
"\"escape\" = \"cancel\"\n"
|
||||||
"\"ctrl+q\" = \"quit\"\n";
|
"\"ctrl+q\" = \"quit\"\n"
|
||||||
|
"\"p\" = \"pause\"\n"
|
||||||
|
"\"n\" = \"step\"\n"
|
||||||
|
"\"+\" = \"speed_up\"\n"
|
||||||
|
"\"-\" = \"speed_down\"\n";
|
||||||
|
|
||||||
int config_ensure_default_file(const char *path) {
|
int config_ensure_default_file(const char *path) {
|
||||||
if (!path) return -1;
|
if (!path) return -1;
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
schema: spec-driven
|
||||||
|
created: 2026-11-08
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Design
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Input, placement, HiDPI, and grid are implemented. Simulation state (`sim_paused`, `ACTION_PAUSE`, `ACTION_STEP`, speed actions) exists but is unused. See proposal.md.
|
||||||
|
|
||||||
|
## Goals / Non-Goals
|
||||||
|
|
||||||
|
**Goals:**
|
||||||
|
- Conway tick loop with adjustable interval.
|
||||||
|
- Pause/resume, stepping, speed control.
|
||||||
|
- Paused-only cell editing via mouse, including drag painting.
|
||||||
|
|
||||||
|
**Non-Goals:**
|
||||||
|
- Pattern detection or statistics.
|
||||||
|
- Undo/redo.
|
||||||
|
- Multi-threading.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
### D1: Tick timing
|
||||||
|
- Use monotonic clock in the frame loop; accumulate elapsed time; when >= interval, compute next generation and reset accumulator.
|
||||||
|
|
||||||
|
### D2: Next generation buffer
|
||||||
|
- Allocate a second grid buffer; compute into it, then swap pointers (or copy). Prefer swap of `cells` pointers with size unchanged.
|
||||||
|
|
||||||
|
### D3: Editing while paused
|
||||||
|
- Pointer button handler sets/clears cells if `sim_paused`; drag paints using motion events while button held.
|
||||||
|
|
||||||
|
### D4: Speed bounds
|
||||||
|
- Interval range 0.05s..1.0s (20 tps..1 tps), step factor 2.
|
||||||
|
|
||||||
|
### D5: Default bindings
|
||||||
|
- Add `p`, `n`, `+`/`-` to default config (merge).
|
||||||
|
|
||||||
|
## Risks / Trade-offs
|
||||||
|
|
||||||
|
- [Tick cost on large grids] -> grid is small (50x50), fine.
|
||||||
|
- [Editing during tick race] -> editing only while paused avoids races.
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
None.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Proposal
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
The application now supports input, pattern placement, and HiDPI rendering, but has no Game of Life dynamics. This change adds the actual automaton: Conway's rules, pause/resume, single stepping, speed control, and mouse editing of cells, so the tool becomes usable for exploring patterns.
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
|
||||||
|
- Add Conway's Game of Life simulation that updates the cell grid on a timer.
|
||||||
|
- Start paused by default; allow pause/resume, single-step, and speed changes.
|
||||||
|
- Allow mouse editing of cells (left click sets alive, right click sets dead) only while paused, including drag painting.
|
||||||
|
- Add default key bindings for pause (`p`), step (`n`), and speed (`+`/`-`).
|
||||||
|
- Render simulation state and reflect pause/editing in the UI (via stdout status).
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
### New Capabilities
|
||||||
|
|
||||||
|
- `gol-simulation`: Conway rules, tick timing, pause/resume, stepping, speed control, and paused-only editing.
|
||||||
|
|
||||||
|
### Modified Capabilities
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
- Affected code: `wlgol.c`, `grid.c/h` (read during ticks), possibly new `simulation.c/h`.
|
||||||
|
- Reuses existing input/config infrastructure; no new dependencies.
|
||||||
|
- Config defaults updated with simulation keys.
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# Spec Delta
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Defines Conway's Game of Life simulation behavior, including ticking, pause/resume, stepping, speed control, and paused-only cell editing.
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Simulation applies Conway's rules
|
||||||
|
The system SHALL advance the grid by one generation per tick using Conway's rules with wall boundaries.
|
||||||
|
|
||||||
|
#### Scenario: Tick advances grid
|
||||||
|
- **WHEN** a tick occurs
|
||||||
|
- **THEN** each cell's next state follows Conway's rules based on its eight neighbors
|
||||||
|
|
||||||
|
### Requirement: Simulation starts paused
|
||||||
|
The system SHALL start with the simulation paused.
|
||||||
|
|
||||||
|
#### Scenario: Initial state
|
||||||
|
- **WHEN** the application starts
|
||||||
|
- **THEN** the simulation is paused
|
||||||
|
|
||||||
|
### Requirement: Pause can be toggled
|
||||||
|
The system SHALL toggle between paused and running when the pause action is triggered.
|
||||||
|
|
||||||
|
#### Scenario: Toggle pause
|
||||||
|
- **WHEN** the user triggers the pause action
|
||||||
|
- **THEN** the simulation switches between paused and running
|
||||||
|
|
||||||
|
### Requirement: Single step advances one generation
|
||||||
|
The system SHALL advance exactly one generation when the step action is triggered while paused.
|
||||||
|
|
||||||
|
#### Scenario: Step while paused
|
||||||
|
- **WHEN** the simulation is paused and the user triggers step
|
||||||
|
- **THEN** the grid advances by one generation
|
||||||
|
- **AND** the simulation remains paused
|
||||||
|
|
||||||
|
### Requirement: Step is ignored while running
|
||||||
|
The system SHALL ignore the step action while the simulation is running.
|
||||||
|
|
||||||
|
#### Scenario: Step while running
|
||||||
|
- **WHEN** the simulation is running and the user triggers step
|
||||||
|
- **THEN** no extra generation is applied
|
||||||
|
|
||||||
|
### Requirement: Speed is adjustable
|
||||||
|
The system SHALL change the tick interval when speed_up or speed_down is triggered, within supported bounds.
|
||||||
|
|
||||||
|
#### Scenario: Speed up
|
||||||
|
- **WHEN** the user triggers speed_up
|
||||||
|
- **THEN** the tick interval decreases (simulation runs faster)
|
||||||
|
|
||||||
|
#### Scenario: Speed down
|
||||||
|
- **WHEN** the user triggers speed_down
|
||||||
|
- **THEN** the tick interval increases (simulation runs slower)
|
||||||
|
|
||||||
|
### Requirement: Cell editing only while paused
|
||||||
|
The system SHALL allow editing cells only while the simulation is paused.
|
||||||
|
|
||||||
|
#### Scenario: Edit while paused
|
||||||
|
- **WHEN** the simulation is paused and the user clicks a cell
|
||||||
|
- **THEN** the cell state changes according to the mouse button
|
||||||
|
|
||||||
|
#### Scenario: No edit while running
|
||||||
|
- **WHEN** the simulation is running and the user clicks a cell
|
||||||
|
- **THEN** the grid is not modified by the click
|
||||||
|
|
||||||
|
### Requirement: Left click sets cell alive
|
||||||
|
The system SHALL set the clicked cell to alive when the left mouse button is pressed while paused.
|
||||||
|
|
||||||
|
#### Scenario: Set alive
|
||||||
|
- **WHEN** the simulation is paused and the user left-clicks a cell
|
||||||
|
- **THEN** that cell becomes alive
|
||||||
|
|
||||||
|
### Requirement: Right click sets cell dead
|
||||||
|
The system SHALL set the clicked cell to dead when the right mouse button is pressed while paused.
|
||||||
|
|
||||||
|
#### Scenario: Set dead
|
||||||
|
- **WHEN** the simulation is paused and the user right-clicks a cell
|
||||||
|
- **THEN** that cell becomes dead
|
||||||
|
|
||||||
|
### Requirement: Drag paints cells
|
||||||
|
The system SHALL paint cells while dragging with the left button (alive) or right button (dead) while paused.
|
||||||
|
|
||||||
|
#### Scenario: Drag paint
|
||||||
|
- **WHEN** the simulation is paused and the user drags with left button held
|
||||||
|
- **THEN** cells under the cursor become alive
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Tasks
|
||||||
|
|
||||||
|
## 1. Simulation core
|
||||||
|
|
||||||
|
- [x] 1.1 Implement Conway tick using a second grid buffer and swap, verifying a known pattern (blinker) oscillates.
|
||||||
|
- [x] 1.2 Add tick timing in the frame loop with adjustable interval, verifying ticks occur at configured rate.
|
||||||
|
|
||||||
|
## 2. Controls
|
||||||
|
|
||||||
|
- [x] 2.1 Wire pause/step/speed actions to simulation state, verifying pause stops ticks and step advances one generation.
|
||||||
|
- [x] 2.2 Add default key bindings for p/n/+/- and verify config tests pass.
|
||||||
|
|
||||||
|
## 3. Editing
|
||||||
|
|
||||||
|
- [x] 3.1 Implement paused-only cell editing on left/right click, verifying clicks change cell state only when paused.
|
||||||
|
- [x] 3.2 Implement drag painting while paused, verifying drag sets/clears cells.
|
||||||
|
|
||||||
|
## 4. Verification
|
||||||
|
|
||||||
|
- [x] 4.1 Build and run ctest, verifying all tests pass.
|
||||||
|
- [x] 4.2 Manual run: verify pause, step, speed, editing, and Esc.
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# gol-simulation Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Defines Conway's Game of Life simulation behavior, including ticking, pause/resume, stepping, speed control, and paused-only cell editing.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Simulation applies Conway's rules
|
||||||
|
The system SHALL advance the grid by one generation per tick using Conway's rules with wall boundaries.
|
||||||
|
|
||||||
|
#### Scenario: Tick advances grid
|
||||||
|
- **WHEN** a tick occurs
|
||||||
|
- **THEN** each cell's next state follows Conway's rules based on its eight neighbors
|
||||||
|
|
||||||
|
### Requirement: Simulation starts paused
|
||||||
|
The system SHALL start with the simulation paused.
|
||||||
|
|
||||||
|
#### Scenario: Initial state
|
||||||
|
- **WHEN** the application starts
|
||||||
|
- **THEN** the simulation is paused
|
||||||
|
|
||||||
|
### Requirement: Pause can be toggled
|
||||||
|
The system SHALL toggle between paused and running when the pause action is triggered.
|
||||||
|
|
||||||
|
#### Scenario: Toggle pause
|
||||||
|
- **WHEN** the user triggers the pause action
|
||||||
|
- **THEN** the simulation switches between paused and running
|
||||||
|
|
||||||
|
### Requirement: Single step advances one generation
|
||||||
|
The system SHALL advance exactly one generation when the step action is triggered while paused.
|
||||||
|
|
||||||
|
#### Scenario: Step while paused
|
||||||
|
- **WHEN** the simulation is paused and the user triggers step
|
||||||
|
- **THEN** the grid advances by one generation
|
||||||
|
- **AND** the simulation remains paused
|
||||||
|
|
||||||
|
### Requirement: Step is ignored while running
|
||||||
|
The system SHALL ignore the step action while the simulation is running.
|
||||||
|
|
||||||
|
#### Scenario: Step while running
|
||||||
|
- **WHEN** the simulation is running and the user triggers step
|
||||||
|
- **THEN** no extra generation is applied
|
||||||
|
|
||||||
|
### Requirement: Speed is adjustable
|
||||||
|
The system SHALL change the tick interval when speed_up or speed_down is triggered, within supported bounds.
|
||||||
|
|
||||||
|
#### Scenario: Speed up
|
||||||
|
- **WHEN** the user triggers speed_up
|
||||||
|
- **THEN** the tick interval decreases (simulation runs faster)
|
||||||
|
|
||||||
|
#### Scenario: Speed down
|
||||||
|
- **WHEN** the user triggers speed_down
|
||||||
|
- **THEN** the tick interval increases (simulation runs slower)
|
||||||
|
|
||||||
|
### Requirement: Cell editing only while paused
|
||||||
|
The system SHALL allow editing cells only while the simulation is paused.
|
||||||
|
|
||||||
|
#### Scenario: Edit while paused
|
||||||
|
- **WHEN** the simulation is paused and the user clicks a cell
|
||||||
|
- **THEN** the cell state changes according to the mouse button
|
||||||
|
|
||||||
|
#### Scenario: No edit while running
|
||||||
|
- **WHEN** the simulation is running and the user clicks a cell
|
||||||
|
- **THEN** the grid is not modified by the click
|
||||||
|
|
||||||
|
### Requirement: Left click sets cell alive
|
||||||
|
The system SHALL set the clicked cell to alive when the left mouse button is pressed while paused.
|
||||||
|
|
||||||
|
#### Scenario: Set alive
|
||||||
|
- **WHEN** the simulation is paused and the user left-clicks a cell
|
||||||
|
- **THEN** that cell becomes alive
|
||||||
|
|
||||||
|
### Requirement: Right click sets cell dead
|
||||||
|
The system SHALL set the clicked cell to dead when the right mouse button is pressed while paused.
|
||||||
|
|
||||||
|
#### Scenario: Set dead
|
||||||
|
- **WHEN** the simulation is paused and the user right-clicks a cell
|
||||||
|
- **THEN** that cell becomes dead
|
||||||
|
|
||||||
|
### Requirement: Drag paints cells
|
||||||
|
The system SHALL paint cells while dragging with the left button (alive) or right button (dead) while paused.
|
||||||
|
|
||||||
|
#### Scenario: Drag paint
|
||||||
|
- **WHEN** the simulation is paused and the user drags with left button held
|
||||||
|
- **THEN** cells under the cursor become alive
|
||||||
@@ -48,11 +48,18 @@ double current_scale = 1.0;
|
|||||||
int need_resize = 1;
|
int need_resize = 1;
|
||||||
|
|
||||||
grid_t grid;
|
grid_t grid;
|
||||||
|
grid_t grid_back;
|
||||||
|
int sim_paused = 1;
|
||||||
|
double sim_interval = 0.05; /* 20 tps */
|
||||||
|
double sim_accumulator = 0.0;
|
||||||
|
struct timespec sim_last_time;
|
||||||
|
int sim_time_initialized = 0;
|
||||||
|
int mouse_left_down = 0;
|
||||||
|
int mouse_right_down = 0;
|
||||||
double cursor_x = 0, cursor_y = 0;
|
double cursor_x = 0, cursor_y = 0;
|
||||||
int click_pending = 0;
|
int click_pending = 0;
|
||||||
double click_x = 0, click_y = 0;
|
double click_x = 0, click_y = 0;
|
||||||
int show_grid_lines = 1;
|
int show_grid_lines = 1;
|
||||||
int sim_paused = 1;
|
|
||||||
struct timespec mytime;
|
struct timespec mytime;
|
||||||
|
|
||||||
struct canvas
|
struct canvas
|
||||||
@@ -229,6 +236,8 @@ const struct wl_buffer_listener wl_buffer_listener = {
|
|||||||
|
|
||||||
void redraw(); // forward declaration
|
void redraw(); // forward declaration
|
||||||
|
|
||||||
|
static void simulation_tick(void);
|
||||||
|
|
||||||
static void handle_key(uint32_t key, uint32_t state, xkb_keysym_t sym, uint32_t mods, void *user_data)
|
static void handle_key(uint32_t key, uint32_t state, xkb_keysym_t sym, uint32_t mods, void *user_data)
|
||||||
{
|
{
|
||||||
(void)key;
|
(void)key;
|
||||||
@@ -266,12 +275,25 @@ static void handle_key(uint32_t key, uint32_t state, xkb_keysym_t sym, uint32_t
|
|||||||
break;
|
break;
|
||||||
case ACTION_PAUSE:
|
case ACTION_PAUSE:
|
||||||
sim_paused = !sim_paused;
|
sim_paused = !sim_paused;
|
||||||
|
sim_accumulator = 0;
|
||||||
|
printf("paused=%d\n", sim_paused);
|
||||||
break;
|
break;
|
||||||
case ACTION_STEP:
|
case ACTION_STEP:
|
||||||
printf("step requested\n");
|
if (sim_paused) {
|
||||||
|
simulation_tick();
|
||||||
|
printf("stepped\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_SPEED_UP:
|
case ACTION_SPEED_UP:
|
||||||
|
sim_interval /= 2.0;
|
||||||
|
if (sim_interval < 0.025) sim_interval = 0.025;
|
||||||
|
printf("interval=%g\n", sim_interval);
|
||||||
|
break;
|
||||||
case ACTION_SPEED_DOWN:
|
case ACTION_SPEED_DOWN:
|
||||||
|
sim_interval *= 2.0;
|
||||||
|
if (sim_interval > 1.0) sim_interval = 1.0;
|
||||||
|
printf("interval=%g\n", sim_interval);
|
||||||
|
break;
|
||||||
case ACTION_TOGGLE_GRID:
|
case ACTION_TOGGLE_GRID:
|
||||||
show_grid_lines = !show_grid_lines;
|
show_grid_lines = !show_grid_lines;
|
||||||
break;
|
break;
|
||||||
@@ -283,12 +305,24 @@ static void handle_key(uint32_t key, uint32_t state, xkb_keysym_t sym, uint32_t
|
|||||||
static void handle_button(uint32_t button, uint32_t state, double x, double y, void *user_data)
|
static void handle_button(uint32_t button, uint32_t state, double x, double y, void *user_data)
|
||||||
{
|
{
|
||||||
(void)user_data;
|
(void)user_data;
|
||||||
if (state != WL_POINTER_BUTTON_STATE_PRESSED) return;
|
if (button == BTN_LEFT) {
|
||||||
if (button != BTN_LEFT) return;
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
click_x = x;
|
mouse_left_down = 1;
|
||||||
click_y = y;
|
click_x = x;
|
||||||
click_pending = 1;
|
click_y = y;
|
||||||
printf("click at %.1f %.1f\n", x, y);
|
click_pending = 1;
|
||||||
|
} else {
|
||||||
|
mouse_left_down = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (button == BTN_RIGHT) {
|
||||||
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
|
mouse_right_down = 1;
|
||||||
|
} else {
|
||||||
|
mouse_right_down = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("button %u state %u at %.1f %.1f\n", button, state, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wl_callack_done(void *data, struct wl_callback *callback, uint32_t time)
|
void wl_callack_done(void *data, struct wl_callback *callback, uint32_t time)
|
||||||
@@ -342,6 +376,7 @@ static void canvas_resize(int log_w, int log_h, double scale) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
grid_resize(&grid, log_w / 8, log_h / 8);
|
grid_resize(&grid, log_w / 8, log_h / 8);
|
||||||
|
grid_resize(&grid_back, grid.cols, grid.rows);
|
||||||
need_resize = 0;
|
need_resize = 0;
|
||||||
printf("canvas resized logical=%dx%d phys=%dx%d scale=%g grid=%dx%d\n", log_w, log_h, phys_w, phys_h, scale, grid.cols, grid.rows);
|
printf("canvas resized logical=%dx%d phys=%dx%d scale=%g grid=%dx%d\n", log_w, log_h, phys_w, phys_h, scale, grid.cols, grid.rows);
|
||||||
}
|
}
|
||||||
@@ -462,6 +497,39 @@ static void fill_rect(int x0, int y0, int w, int h, unsigned char r, unsigned ch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int count_neighbors(int c, int r) {
|
||||||
|
int n = 0;
|
||||||
|
for (int dr = -1; dr <= 1; dr++) {
|
||||||
|
for (int dc = -1; dc <= 1; dc++) {
|
||||||
|
if (dr == 0 && dc == 0) continue;
|
||||||
|
n += grid_get(&grid, c + dc, r + dr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void simulation_tick(void) {
|
||||||
|
if (grid_back.cols != grid.cols || grid_back.rows != grid.rows) {
|
||||||
|
grid_free(&grid_back);
|
||||||
|
grid_init(&grid_back, grid.cols, grid.rows);
|
||||||
|
}
|
||||||
|
grid_clear(&grid_back);
|
||||||
|
for (int r = 0; r < grid.rows; r++) {
|
||||||
|
for (int c = 0; c < grid.cols; c++) {
|
||||||
|
int alive = grid_get(&grid, c, r);
|
||||||
|
int nb = count_neighbors(c, r);
|
||||||
|
int next = 0;
|
||||||
|
if (alive && (nb == 2 || nb == 3)) next = 1;
|
||||||
|
if (!alive && nb == 3) next = 1;
|
||||||
|
grid_set(&grid_back, c, r, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* swap cell buffers */
|
||||||
|
unsigned char *tmp = grid.cells;
|
||||||
|
grid.cells = grid_back.cells;
|
||||||
|
grid_back.cells = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
void redraw()
|
void redraw()
|
||||||
{
|
{
|
||||||
if (need_resize) {
|
if (need_resize) {
|
||||||
@@ -474,6 +542,35 @@ void redraw()
|
|||||||
cursor_x = pointer_data.x;
|
cursor_x = pointer_data.x;
|
||||||
cursor_y = pointer_data.y;
|
cursor_y = pointer_data.y;
|
||||||
|
|
||||||
|
/* tick timing */
|
||||||
|
struct timespec now;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
if (!sim_time_initialized) {
|
||||||
|
sim_last_time = now;
|
||||||
|
sim_time_initialized = 1;
|
||||||
|
}
|
||||||
|
double dt = (now.tv_sec - sim_last_time.tv_sec) + (now.tv_nsec - sim_last_time.tv_nsec) / 1e9;
|
||||||
|
sim_last_time = now;
|
||||||
|
if (!sim_paused) {
|
||||||
|
sim_accumulator += dt;
|
||||||
|
while (sim_accumulator >= sim_interval) {
|
||||||
|
simulation_tick();
|
||||||
|
sim_accumulator -= sim_interval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* paused-only editing */
|
||||||
|
if (sim_paused && active_tool < 0) {
|
||||||
|
if (mouse_left_down || mouse_right_down) {
|
||||||
|
int cx = (int)(cursor_x / 8.0);
|
||||||
|
int cy = (int)(cursor_y / 8.0);
|
||||||
|
if (cx >= 0 && cy >= 0 && cx < grid.cols && cy < grid.rows) {
|
||||||
|
if (mouse_left_down) grid_set(&grid, cx, cy, 1);
|
||||||
|
if (mouse_right_down) grid_set(&grid, cx, cy, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* handle pending click placement */
|
/* handle pending click placement */
|
||||||
if (click_pending) {
|
if (click_pending) {
|
||||||
click_pending = 0;
|
click_pending = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user