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 }