6 #include "game/camera.h"
7 #include "system/line_stream.h"
8 #include "system/log.h"
10 #include "system/nth_alloc.h"
11 #include "system/stacktrace.h"
12 #include "system/str.h"
13 #include "ui/edit_field.h"
14 #include "./point_layer.h"
15 #include "math/extrema.h"
16 #include "./color_picker.h"
17 #include "undo_history.h"
19 #define POINT_LAYER_ELEMENT_RADIUS 10.0f
20 #define POINT_LAYER_ID_TEXT_SIZE vec(2.0f, 2.0f)
21 #define POINT_LAYER_ID_TEXT_COLOR COLOR_BLACK
23 // TODO(#1002): PointLayer does not fully support UndoHistory
34 PointLayerState state;
35 Dynarray/*<Point>*/ *positions;
36 Dynarray/*<Color>*/ *colors;
37 Dynarray/*<char[ID_MAX_SIZE]>*/ *ids;
38 Edit_field *edit_field;
40 ColorPicker color_picker;
43 LayerPtr point_layer_as_layer(PointLayer *point_layer)
52 PointLayer *create_point_layer(void)
56 PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free);
57 if (point_layer == NULL) {
62 point_layer->state = POINT_LAYER_IDLE;
64 point_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
65 if (point_layer->positions == NULL) {
69 point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
70 if (point_layer->colors == NULL) {
74 point_layer->ids = PUSH_LT(lt, create_dynarray(sizeof(char) * ID_MAX_SIZE), destroy_dynarray);
75 if (point_layer->ids == NULL) {
79 point_layer->edit_field = PUSH_LT(
82 POINT_LAYER_ID_TEXT_SIZE,
83 POINT_LAYER_ID_TEXT_COLOR),
85 if (point_layer->edit_field == NULL) {
92 PointLayer *create_point_layer_from_line_stream(LineStream *line_stream)
94 trace_assert(line_stream);
96 PointLayer *point_layer = create_point_layer();
100 line_stream_next(line_stream),
103 log_fail("Could not read amount of points");
104 RETURN_LT(point_layer->lt, NULL);
108 char id[ID_MAX_SIZE];
110 for (size_t i = 0; i < count; ++i) {
112 line_stream_next(line_stream),
113 "%"STRINGIFY(ID_MAX_SIZE)"s%f%f%6s",
114 id, &x, &y, color_name) < 0) {
115 log_fail("Could not read %dth goal\n", i);
116 RETURN_LT(point_layer->lt, NULL);
118 const Color color = hexstr(color_name);
119 const Point point = vec(x, y);
121 dynarray_push(point_layer->colors, &color);
122 dynarray_push(point_layer->positions, &point);
123 dynarray_push(point_layer->ids, id);
126 point_layer->selected = -1;
128 point_layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
133 void destroy_point_layer(PointLayer *point_layer)
135 trace_assert(point_layer);
136 RETURN_LT0(point_layer->lt);
139 int point_layer_render(const PointLayer *point_layer,
143 trace_assert(point_layer);
144 trace_assert(camera);
146 const int n = (int) dynarray_count(point_layer->positions);
147 Point *positions = dynarray_data(point_layer->positions);
148 Color *colors = dynarray_data(point_layer->colors);
149 char *ids = dynarray_data(point_layer->ids);
151 for (int i = 0; i < n; ++i) {
152 const Triangle t = triangle_mat3x3_product(
153 equilateral_triangle(),
155 trans_mat(positions[i].x, positions[i].y),
156 scale_mat(POINT_LAYER_ELEMENT_RADIUS)));
158 const Color color = color_scale(
160 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f));
162 if (i == point_layer->selected) {
163 const Triangle t0 = triangle_mat3x3_product(
164 equilateral_triangle(),
166 trans_mat(positions[i].x, positions[i].y),
169 if (camera_fill_triangle(camera, t0, color_invert(color)) < 0) {
173 if (point_layer->state != POINT_LAYER_EDIT_ID &&
176 ids + ID_MAX_SIZE * i,
177 POINT_LAYER_ID_TEXT_SIZE,
178 POINT_LAYER_ID_TEXT_COLOR,
184 if (camera_fill_triangle(camera, t, color) < 0) {
190 if (point_layer->state == POINT_LAYER_EDIT_ID) {
191 if (edit_field_render_world(
192 point_layer->edit_field,
194 positions[point_layer->selected]) < 0) {
199 if (active && color_picker_render(&point_layer->color_picker, camera) < 0) {
208 int point_layer_element_at(const PointLayer *point_layer,
211 trace_assert(point_layer);
213 int n = (int) dynarray_count(point_layer->positions);
214 Point *positions = dynarray_data(point_layer->positions);
216 for (int i = 0; i < n; ++i) {
217 if (vec_length(vec_sub(positions[i], position)) < POINT_LAYER_ELEMENT_RADIUS) {
226 void point_layer_pop_element(void *layer, Context context)
231 PointLayer *point_layer = layer;
233 dynarray_pop(point_layer->positions, NULL);
234 dynarray_pop(point_layer->colors, NULL);
235 dynarray_pop(point_layer->ids, NULL);
239 int point_layer_add_element(PointLayer *point_layer,
242 UndoHistory *undo_history)
244 trace_assert(point_layer);
245 trace_assert(undo_history);
247 char id[ID_MAX_SIZE];
248 for (size_t i = 0; i < ID_MAX_SIZE - 1; ++i) {
249 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
251 id[ID_MAX_SIZE - 1] = '\0';
253 dynarray_push(point_layer->positions, &position);
254 dynarray_push(point_layer->colors, &color);
255 dynarray_push(point_layer->ids, id);
258 .revert = point_layer_pop_element,
261 undo_history_push(undo_history, action);
267 void point_layer_delete_nth_element(PointLayer *point_layer,
270 trace_assert(point_layer);
271 dynarray_delete_at(point_layer->positions, i);
272 dynarray_delete_at(point_layer->colors, i);
273 dynarray_delete_at(point_layer->ids, i);
277 int point_layer_idle_event(PointLayer *point_layer,
278 const SDL_Event *event,
279 const Camera *camera,
280 UndoHistory *undo_history)
282 trace_assert(point_layer);
284 trace_assert(camera);
287 if (color_picker_event(
288 &point_layer->color_picker,
295 if (point_layer->selected >= 0) {
296 Color *colors = dynarray_data(point_layer->colors);
297 colors[point_layer->selected] =
298 color_picker_rgba(&point_layer->color_picker);
304 switch (event->type) {
305 case SDL_MOUSEBUTTONDOWN: {
306 switch (event->button.button) {
307 case SDL_BUTTON_LEFT: {
308 const Point position = camera_map_screen(camera, event->button.x, event->button.y);
310 point_layer->selected = point_layer_element_at(
311 point_layer, position);
313 if (point_layer->selected < 0) {
314 point_layer_add_element(
317 color_picker_rgba(&point_layer->color_picker),
320 Color *colors = dynarray_data(point_layer->colors);
321 point_layer->state = POINT_LAYER_MOVE;
322 point_layer->color_picker =
323 create_color_picker_from_rgba(colors[point_layer->selected]);
330 switch (event->key.keysym.sym) {
332 if (0 <= point_layer->selected && point_layer->selected < (int) dynarray_count(point_layer->positions)) {
333 point_layer_delete_nth_element(point_layer, (size_t)point_layer->selected);
334 point_layer->selected = -1;
339 if (point_layer->selected >= 0) {
340 char *ids = dynarray_data(point_layer->ids);
341 point_layer->state = POINT_LAYER_EDIT_ID;
343 point_layer->edit_field,
344 ids + ID_MAX_SIZE * point_layer->selected);
345 SDL_StartTextInput();
356 int point_layer_edit_id_event(PointLayer *point_layer,
357 const SDL_Event *event,
358 const Camera *camera)
360 trace_assert(point_layer);
362 trace_assert(camera);
364 switch (event->type) {
366 switch(event->key.keysym.sym) {
368 char *ids = dynarray_data(point_layer->ids);
369 const char *text = edit_field_as_text(point_layer->edit_field);
370 size_t n = max_size_t(strlen(text), ID_MAX_SIZE - 1);
371 memcpy(ids + point_layer->selected * ID_MAX_SIZE, text, n);
372 *(ids + point_layer->selected * ID_MAX_SIZE + n) = '\0';
373 point_layer->state = POINT_LAYER_IDLE;
379 point_layer->state = POINT_LAYER_IDLE;
387 return edit_field_event(point_layer->edit_field, event);
391 int point_layer_move_event(PointLayer *point_layer,
392 const SDL_Event *event,
393 const Camera *camera)
395 trace_assert(point_layer);
397 trace_assert(camera);
398 trace_assert(point_layer->selected >= 0);
400 switch (event->type) {
401 case SDL_MOUSEBUTTONUP: {
402 switch (event->button.button) {
403 case SDL_BUTTON_LEFT: {
404 point_layer->state = POINT_LAYER_IDLE;
409 case SDL_MOUSEMOTION: {
410 Point *positions = dynarray_data(point_layer->positions);
411 positions[point_layer->selected] =
412 camera_map_screen(camera, event->motion.x, event->motion.y);
419 int point_layer_event(PointLayer *point_layer,
420 const SDL_Event *event,
421 const Camera *camera,
422 UndoHistory *undo_history)
424 trace_assert(point_layer);
426 trace_assert(camera);
427 trace_assert(undo_history);
429 switch (point_layer->state) {
430 case POINT_LAYER_IDLE:
431 return point_layer_idle_event(point_layer, event, camera, undo_history);
433 case POINT_LAYER_EDIT_ID:
434 return point_layer_edit_id_event(point_layer, event, camera);
436 case POINT_LAYER_MOVE:
437 return point_layer_move_event(point_layer, event, camera);
443 size_t point_layer_count(const PointLayer *point_layer)
445 trace_assert(point_layer);
446 return dynarray_count(point_layer->positions);
449 const Point *point_layer_positions(const PointLayer *point_layer)
451 trace_assert(point_layer);
452 return dynarray_data(point_layer->positions);
455 const Color *point_layer_colors(const PointLayer *point_layer)
457 trace_assert(point_layer);
458 return dynarray_data(point_layer->colors);
461 const char *point_layer_ids(const PointLayer *point_layer)
463 trace_assert(point_layer);
464 return dynarray_data(point_layer->ids);
467 int point_layer_dump_stream(const PointLayer *point_layer,
470 trace_assert(point_layer);
471 trace_assert(filedump);
473 size_t n = dynarray_count(point_layer->ids);
474 char *ids = dynarray_data(point_layer->ids);
475 Point *positions = dynarray_data(point_layer->positions);
476 Color *colors = dynarray_data(point_layer->colors);
478 fprintf(filedump, "%zd\n", n);
479 for (size_t i = 0; i < n; ++i) {
480 fprintf(filedump, "%s %f %f ",
481 ids + ID_MAX_SIZE * i,
482 positions[i].x, positions[i].y);
483 color_hex_to_stream(colors[i], filedump);
484 fprintf(filedump, "\n");