1 /*
2 * Copyright (C) 2014 Tomasz Kramkowski <tk@the-tk.com>
3 *
4 * This program is free software. It is licensed under version 3 of the
5 * GNU General Public License.
6 *
7 * You should have received a copy of the GNU General Public License
8 * along with this program. If not, see [http://www.gnu.org/licenses/].
9 */
10 #include <stdbool.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <time.h>
14 #include <xcb/xcb.h>
15 #include <xcb/xcb_image.h>
16
17 #define BOARD_WIDTH 500
18 #define BOARD_HEIGHT 500
19
20 #define PIXEL 1
21
22 #define WIDTH (BOARD_WIDTH * PIXEL)
23 #define HEIGHT (BOARD_HEIGHT * PIXEL)
24
25 #define GOL_CLAMP(pos, max) ((pos) < 0 ? (pos) + (max) : (pos) % (max))
26 #define GOL_CLAMPX(gol, pos) (GOL_CLAMP((pos), (gol)->width))
27 #define GOL_CLAMPY(gol, pos) (GOL_CLAMP((pos), (gol)->height))
28 #define GOL_RESOLVE_F(gol, x, y) ((gol)->buffers[(gol)->front][(GOL_CLAMPX(gol, x))\
29 + (GOL_CLAMPY(gol, y)) * (gol)->width])
30 #define GOL_RESOLVE_B(gol, x, y) ((gol)->buffers[!(gol)->front][(GOL_CLAMPX(gol, x))\
31 + (GOL_CLAMPY(gol, y)) * (gol)->width])
32
33 typedef struct gol_t {
34 uint32_t width, height;
35 bool *buffers[2];
36 uint8_t front;
37 } Gol;
38
39 Gol *gol_new(unsigned const int width, unsigned const int height)
40 {
41 Gol *gol = malloc(sizeof(Gol));
42 gol->width = width;
43 gol->height = height;
44 gol->front = 0;
45 gol->buffers[0] = malloc(width * height * sizeof(bool));
46 gol->buffers[1] = malloc(width * height * sizeof(bool));
47 return gol;
48 }
49
50 void gol_del(Gol *gol)
51 {
52 free(gol->buffers[0]);
53 free(gol->buffers[1]);
54 free(gol);
55 }
56
57 void gol_random(Gol *const gol, unsigned const int seed)
58 {
59 srand(seed);
60 for (uint32_t i = 0; i < gol->width * gol->height; i++)
61 gol->buffers[gol->front][i] = rand() < 0.5 * ((double)RAND_MAX + 1.0);
62 }
63
64 static uint32_t gol_clamp(const uint32_t pos, const uint32_t max) {
65 return pos < 0 ? pos + max : pos % max;
66 }
67
68 static uint32_t gol_resolve_f(const Gol *const gol,
69
70 static uint8_t gol_neighbours(Gol *const gol, const uint32_t x, const uint32_t y)
71 {
72 uint8_t neighbours = 0;
73 for (int8_t dx = -1; dx <= 1; dx++)
74 for (int8_t dy = -1; dy <= 1; dy++)
75 if (!(dx == 0 && dy == 0) && GOL_RESOLVE_F(gol, x + dx, y + dy))
76 neighbours++;
77 return neighbours;
78 }
79
80 void gol_simulate(Gol *const gol)
81 {
82 for (uint32_t x = 0; x < gol->width; x++)
83 for (uint32_t y = 0; y < gol->height; y++) {
84 uint8_t neighbours = gol_neighbours(gol, x, y);
85 if (GOL_RESOLVE_F(gol, x, y)){
86 if (neighbours < 2)
87 GOL_RESOLVE_B(gol, x, y) = 0;
88 else if (neighbours <= 3)
89 GOL_RESOLVE_B(gol, x, y) = 1;
90 else
91 GOL_RESOLVE_B(gol, x, y) = 0;
92 } else {
93 if (neighbours == 3)
94 GOL_RESOLVE_B(gol, x, y) = 1;
95 else
96 GOL_RESOLVE_B(gol, x, y) = 0;
97 }
98 }
99
100 gol->front = !gol->front;
101 }
102
103 int main(int argc, char **argv)
104 {
105 xcb_connection_t *connection = xcb_connect(NULL, NULL);
106
107 xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
108
109 uint32_t mask = XCB_CW_BACK_PIXEL;
110 uint32_t values[] = {screen->black_pixel};
111
112 xcb_drawable_t window = xcb_generate_id(connection);
113 xcb_create_window(connection,
114 24,
115 window,
116 screen->root,
117 0, 0,
118 WIDTH, HEIGHT,
119 1,
120 XCB_WINDOW_CLASS_INPUT_OUTPUT,
121 screen->root_visual,
122 mask, values);
123
124 xcb_pixmap_t pixmap = xcb_generate_id(connection);
125 xcb_create_pixmap(connection,
126 24,
127 pixmap,
128 window,
129 WIDTH, HEIGHT);
130
131 uint8_t *img = malloc(WIDTH * HEIGHT * 4);
132 xcb_image_t *image = xcb_image_create(WIDTH, HEIGHT,
133 XCB_IMAGE_FORMAT_Z_PIXMAP,
134 8, 24, 32,
135 0,
136 XCB_IMAGE_ORDER_MSB_FIRST,
137 XCB_IMAGE_ORDER_LSB_FIRST,
138 img,
139 WIDTH * HEIGHT * 4,
140 img);
141
142 mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
143 values[0] = screen->black_pixel;
144 values[1] = 0xFFFFFF;
145
146 xcb_gcontext_t gc = xcb_generate_id(connection);
147 xcb_create_gc(connection,
148 gc,
149 pixmap,
150 mask, values);
151
152 xcb_image_put(connection, pixmap, gc, image, 0, 0, 0);
153
154 xcb_map_window(connection, window);
155 xcb_flush(connection);
156
157 uint8_t value = 0;
158
159 uint32_t *limg;
160
161 Gol *gol = gol_new(BOARD_WIDTH, BOARD_HEIGHT);
162 gol_random(gol, time(NULL));
163
164 while (1) {
165 limg = (uint32_t *)image->data;
166
167 for (int i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; i++)
168 *(limg++) = gol->buffers[gol->front][i] ? 0x00FFFF00 : 0x00000000;
169
170 xcb_image_put(connection, pixmap, gc, image, 0, 0, 0);
171
172 xcb_copy_area(connection,
173 pixmap,
174 window,
175 gc,
176 0, 0,
177 0, 0,
178 WIDTH, HEIGHT);
179 xcb_flush(connection);
180 value++;
181
182 gol_simulate(gol);
183 }
184 return 0;
185 }