ajwillia-ms pushed a commit to branch master. http://git.enlightenment.org/tools/examples.git/commit/?id=fc7503113a18ff5da384fce24214dde7c17c7941
commit fc7503113a18ff5da384fce24214dde7c17c7941 Author: Andy Williams <a...@andywilliams.me> Date: Fri Dec 1 22:27:35 2017 +0000 apps: Add first pass Game of Life :) --- apps/c/life/meson.build | 13 ++++ apps/c/life/src/life_board.c | 162 +++++++++++++++++++++++++++++++++++++++++ apps/c/life/src/life_main.c | 90 +++++++++++++++++++++++ apps/c/life/src/life_private.h | 25 +++++++ apps/c/life/src/life_render.c | 93 +++++++++++++++++++++++ apps/c/life/src/meson.build | 14 ++++ 6 files changed, 397 insertions(+) diff --git a/apps/c/life/meson.build b/apps/c/life/meson.build new file mode 100644 index 0000000..06c1dc7 --- /dev/null +++ b/apps/c/life/meson.build @@ -0,0 +1,13 @@ +project( + 'efl-example-life', 'c', + version : '0.0.1', + default_options: [ 'c_std=gnu99', 'warning_level=2' ], + meson_version : '>= 0.38.0') + +eina = dependency('eina', version : '>=1.20.99') +efl = dependency('efl-ui', version : '>=1.20.99') +elm = dependency('elementary', version : '>=1.20.99') + +inc = include_directories('.') +subdir('src') + diff --git a/apps/c/life/src/life_board.c b/apps/c/life/src/life_board.c new file mode 100644 index 0000000..40884d4 --- /dev/null +++ b/apps/c/life/src/life_board.c @@ -0,0 +1,162 @@ +#define EFL_EO_API_SUPPORT 1 +#define EFL_BETA_API_SUPPORT 1 + +#include <Elementary.h> +#include <Efl_Ui.h> + +#include "life_private.h" + +static int gen = 0; + +int *life_board, *life_board_prev; +static int *_life_board_1, *_life_board_2; +static Efl_Loop_Timer *_life_timer; + +static void +_life_tick(void *data, const Efl_Event *event EINA_UNUSED) +{ + Efl_Ui_Win *win = data; + + life_board_nextgen(); + life_render_refresh(win); +} + +static void +_life_cell_on(int x, int y) +{ + _life_board_1[life_render_index_for_position(x, y)] = 1; +} + +static void +_life_board_setup() +{ + // glide + _life_cell_on(16, 1); + _life_cell_on(17, 2); + _life_cell_on(18, 2); + _life_cell_on(16, 3); + _life_cell_on(17, 3); + + // oscilate + _life_cell_on(22, 15); + _life_cell_on(23, 15); + _life_cell_on(24, 15); + + // block + _life_cell_on(32, 15); + _life_cell_on(33, 15); + _life_cell_on(32, 16); + _life_cell_on(33, 16); +} + +void +life_board_init() +{ + _life_board_1 = calloc(1, sizeof(int) * LIFE_BOARD_WIDTH * LIFE_BOARD_HEIGHT); + _life_board_2 = calloc(1, sizeof(int) * LIFE_BOARD_WIDTH * LIFE_BOARD_HEIGHT); + + _life_board_setup(); + + life_board = _life_board_1; + life_board_prev = _life_board_2; +} + +void +life_board_run(Efl_Ui_Win *win) +{ + _life_timer = efl_add(EFL_LOOP_TIMER_CLASS, NULL, + efl_loop_timer_interval_set(efl_added, 0.1)); + + efl_event_callback_add(_life_timer, EFL_LOOP_TIMER_EVENT_TICK, _life_tick, win); +} + +int +life_board_sum_around(int x, int y) +{ + int sum = 0; + int i, max; + + max = LIFE_BOARD_WIDTH * LIFE_BOARD_HEIGHT; + + i = life_render_index_for_position(x - 1, (y - 1)); + if (i >= 0) + sum += life_board[i]; + i++; + if (i >= 0) + sum += life_board[i]; + i++; + if (i >= 0) + sum += life_board[i]; + + i = life_render_index_for_position(x - 1, y); + if (i >= 0) + sum += life_board[i]; + i += 2; + if (i < max) + sum += life_board[i]; + + i = life_render_index_for_position(x - 1, (y + 1)); + if (i < max) + sum += life_board[i]; + i++; + if (i < max) + sum += life_board[i]; + i++; + if (i < max) + sum += life_board[i]; + + return sum; +} + +void +life_board_nextgen() +{ + int *work; + int x, y, i, n; + gen++; + + if (life_board == _life_board_1) + work = _life_board_2; + else + work = _life_board_1; + + for (y = 0; y < LIFE_BOARD_HEIGHT; y++) + for (x = 0; x < LIFE_BOARD_WIDTH; x++) + { + i = life_render_index_for_position(x, y); + + n = life_board_sum_around(x, y); + if (life_board[i]) + { + if (n > 3 || n < 2) + work[i] = 0; + else + work[i] = 1; + } + else + { + if (n == 3) + work[i] = 1; + else + work[i] = 0; + } + } + + life_board_prev = life_board; + life_board = work; +} + +void +life_board_pause_toggle(Efl_Ui_Win *win) +{ + if (_life_timer) + { + efl_del(_life_timer); + _life_timer = NULL; + } + else + { + life_board_run(win); + } +} + diff --git a/apps/c/life/src/life_main.c b/apps/c/life/src/life_main.c new file mode 100644 index 0000000..63f97f8 --- /dev/null +++ b/apps/c/life/src/life_main.c @@ -0,0 +1,90 @@ +#define EFL_EO_API_SUPPORT 1 +#define EFL_BETA_API_SUPPORT 1 + +#include <Elementary.h> +#include <Efl_Ui.h> + +#include "life_private.h" + +static void +_life_win_resize(void *data EINA_UNUSED, const Efl_Event *event) +{ + Efl_Ui_Win *win = event->object; + + life_render_layout(win); +} + +static void +_life_win_touch(void *data EINA_UNUSED, const Efl_Event *event) +{ + int cellx, celly, i; + Efl_Input_Pointer *ev; + Efl_Ui_Win *win; + Eina_Position2D position; + + ev = event->info; + win = event->object; + + position = efl_input_pointer_position_get(ev); + life_render_cell_for_coords(win, position, &cellx, &celly); + + i = life_render_index_for_position(cellx, celly); + life_board[i] = !life_board[i]; + life_render_cell(win, cellx, celly); +} + +static void +_life_win_key_down(void *data EINA_UNUSED, const Efl_Event *event) +{ + Efl_Input_Key *ev; + Efl_Ui_Win *win; + + ev = event->info; + win = event->object; + + if (!strcmp(efl_input_key_get(ev), "space")) + life_board_pause_toggle(win); +} + +static Evas_Object * +_life_win_setup(void) +{ + Efl_Ui_Win *win; + Evas_Coord w; + Evas_Coord h; + + win = efl_add(EFL_UI_WIN_CLASS, NULL, + efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC), + efl_text_set(efl_added, "EFL Life"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + if (!win) return NULL; + + // TODO + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + w = 10 * LIFE_BOARD_WIDTH * efl_ui_scale_get(win); + h = 10 * LIFE_BOARD_HEIGHT * efl_ui_scale_get(win); + + life_board_init(); + life_render_init(win); + life_render_refresh(win); + + efl_event_callback_add(win, EFL_GFX_EVENT_RESIZE, _life_win_resize, NULL); + efl_event_callback_add(win, EFL_EVENT_POINTER_DOWN, _life_win_touch, NULL); + efl_event_callback_add(win, EFL_EVENT_KEY_DOWN, _life_win_key_down, NULL); + + efl_gfx_size_set(win, EINA_SIZE2D(w, h)); + + return win; +} + +EAPI_MAIN void +efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) +{ + Efl_Ui_Win *win; + + if (!(win = _life_win_setup())) + efl_exit(1); + + life_board_run(win); +} +EFL_MAIN() diff --git a/apps/c/life/src/life_private.h b/apps/c/life/src/life_private.h new file mode 100644 index 0000000..724c76b --- /dev/null +++ b/apps/c/life/src/life_private.h @@ -0,0 +1,25 @@ +#ifndef LIFE_PRIVATE_H_ +# define LIFE_PRIVATE_H_ + +#include <Elementary.h> +#include <Efl_Ui.h> + +#define LIFE_BOARD_WIDTH 47 +#define LIFE_BOARD_HEIGHT 31 + +extern int *life_board, *life_board_prev; + +void life_board_init(void); + +void life_board_nextgen(void); +void life_board_run(Efl_Ui_Win *win); +void life_board_pause_toggle(Efl_Ui_Win *win); + +void life_render_init(Efl_Ui_Win *win); +void life_render_cell_for_coords(Efl_Ui_Win *win, Eina_Position2D coord, int *x, int *y); +int life_render_index_for_position(int x, int y); +void life_render_layout(Efl_Ui_Win *win); +void life_render_cell(Efl_Ui_Win *win, int x, int y); +void life_render_refresh(Efl_Ui_Win *win); + +#endif diff --git a/apps/c/life/src/life_render.c b/apps/c/life/src/life_render.c new file mode 100644 index 0000000..9fd2da8 --- /dev/null +++ b/apps/c/life/src/life_render.c @@ -0,0 +1,93 @@ +#define EFL_EO_API_SUPPORT 1 +#define EFL_BETA_API_SUPPORT 1 + +#include <Elementary.h> +#include <Efl_Ui.h> + +#include "life_private.h" + +Efl_Canvas_Rectangle **_life_cells; + +void +life_render_init(Efl_Ui_Win *win) +{ + int x, y; + + _life_cells = calloc(1, sizeof(Efl_Canvas_Rectangle *) * LIFE_BOARD_WIDTH * LIFE_BOARD_HEIGHT); + + for (y = 0; y < LIFE_BOARD_HEIGHT; y++) + for (x = 0; x < LIFE_BOARD_WIDTH; x++) + efl_add(EFL_CANVAS_RECTANGLE_CLASS, win, + _life_cells[life_render_index_for_position(x, y)] = efl_added); + + life_render_layout(win); +} + +void +life_render_cell_for_coords(Efl_Ui_Win *win, Eina_Position2D coord, + int *x, int *y) +{ + Eina_Size2D size; + + size = efl_gfx_size_get(win); + + if (x) + *x = coord.x / ((double) size.w / LIFE_BOARD_WIDTH); + if (y) + *y = coord.y / ((double) size.h / LIFE_BOARD_HEIGHT); +} + +int +life_render_index_for_position(int x, int y) +{ + return y * LIFE_BOARD_WIDTH + x; +} + +void +life_render_layout(Efl_Ui_Win *win) +{ + Eina_Size2D size; + double cw, ch; + Evas_Object *rect; + int x, y; + + size = efl_gfx_size_get(win); + cw = (double) size.w / LIFE_BOARD_WIDTH; + ch = (double) size.h / LIFE_BOARD_HEIGHT; + + for (y = 0; y < LIFE_BOARD_HEIGHT; y++) + for (x = 0; x < LIFE_BOARD_WIDTH; x++) + { + rect = _life_cells[life_render_index_for_position(x, y)]; + + // the little +1 here will avoid tearing as we layout non-multiple sizes + efl_gfx_size_set(rect, EINA_SIZE2D(cw + 1, ch + 1)); + efl_gfx_position_set(rect, EINA_POSITION2D(x * cw, y * ch)); + } +} + +void +life_render_cell(Efl_Ui_Win *win EINA_UNUSED, int x, int y) +{ + Evas_Object *rect; + int i; + + i = life_render_index_for_position(x, y); + rect = _life_cells[i]; + + if (life_board[i]) + efl_gfx_color_set(rect, 0, 0, 0, 255); + else + efl_gfx_color_set(rect, 255, 255, 255, 255); +} + +void +life_render_refresh(Efl_Ui_Win *win EINA_UNUSED) +{ + int x, y; + + for (y = 0; y < LIFE_BOARD_HEIGHT; y++) + for (x = 0; x < LIFE_BOARD_WIDTH; x++) + life_render_cell(win, x, y); +} + diff --git a/apps/c/life/src/meson.build b/apps/c/life/src/meson.build new file mode 100644 index 0000000..fc95182 --- /dev/null +++ b/apps/c/life/src/meson.build @@ -0,0 +1,14 @@ +src = files([ + 'life_render.c', + 'life_board.c', + 'life_main.c', +]) + +deps = [eina, efl, elm] + +executable('efl_example_life', src, + dependencies : deps, + include_directories : inc, + install : true +) + --