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"
18 #define POINT_LAYER_ELEMENT_RADIUS 10.0f
19 #define POINT_LAYER_ID_TEXT_SIZE vec(2.0f, 2.0f)
20 #define POINT_LAYER_ID_TEXT_COLOR COLOR_BLACK
22 // TODO(#985): PointLayer cannot move its points
32 PointLayerState state;
33 Dynarray/*<Point>*/ *positions;
34 Dynarray/*<Color>*/ *colors;
35 Dynarray/*<char[ID_MAX_SIZE]>*/ *ids;
36 Edit_field *edit_field;
38 ColorPicker color_picker;
41 LayerPtr point_layer_as_layer(PointLayer *point_layer)
50 PointLayer *create_point_layer(void)
54 PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free);
55 if (point_layer == NULL) {
60 point_layer->state = POINT_LAYER_IDLE;
62 point_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
63 if (point_layer->positions == NULL) {
67 point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
68 if (point_layer->colors == NULL) {
72 point_layer->ids = PUSH_LT(lt, create_dynarray(sizeof(char) * ID_MAX_SIZE), destroy_dynarray);
73 if (point_layer->ids == NULL) {
77 point_layer->edit_field = PUSH_LT(
80 POINT_LAYER_ID_TEXT_SIZE,
81 POINT_LAYER_ID_TEXT_COLOR),
83 if (point_layer->edit_field == NULL) {
90 PointLayer *create_point_layer_from_line_stream(LineStream *line_stream)
92 trace_assert(line_stream);
94 PointLayer *point_layer = create_point_layer();
98 line_stream_next(line_stream),
101 log_fail("Could not read amount of points");
102 RETURN_LT(point_layer->lt, NULL);
106 char id[ID_MAX_SIZE];
108 for (size_t i = 0; i < count; ++i) {
110 line_stream_next(line_stream),
111 "%"STRINGIFY(ID_MAX_SIZE)"s%f%f%6s",
112 id, &x, &y, color_name) < 0) {
113 log_fail("Could not read %dth goal\n", i);
114 RETURN_LT(point_layer->lt, NULL);
116 const Color color = hexstr(color_name);
117 const Point point = vec(x, y);
119 dynarray_push(point_layer->colors, &color);
120 dynarray_push(point_layer->positions, &point);
121 dynarray_push(point_layer->ids, id);
124 point_layer->selected = -1;
126 point_layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
131 void destroy_point_layer(PointLayer *point_layer)
133 trace_assert(point_layer);
134 RETURN_LT0(point_layer->lt);
137 int point_layer_render(const PointLayer *point_layer,
141 trace_assert(point_layer);
142 trace_assert(camera);
144 const int n = (int) dynarray_count(point_layer->positions);
145 Point *positions = dynarray_data(point_layer->positions);
146 Color *colors = dynarray_data(point_layer->colors);
147 char *ids = dynarray_data(point_layer->ids);
149 for (int i = 0; i < n; ++i) {
150 const Triangle t = triangle_mat3x3_product(
151 equilateral_triangle(),
153 trans_mat(positions[i].x, positions[i].y),
154 scale_mat(POINT_LAYER_ELEMENT_RADIUS)));
156 const Color color = color_scale(
158 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f));
160 if (i == point_layer->selected) {
161 const Triangle t0 = triangle_mat3x3_product(
162 equilateral_triangle(),
164 trans_mat(positions[i].x, positions[i].y),
167 if (camera_fill_triangle(camera, t0, color_invert(color)) < 0) {
171 if (point_layer->state != POINT_LAYER_EDIT_ID &&
174 ids + ID_MAX_SIZE * i,
175 POINT_LAYER_ID_TEXT_SIZE,
176 POINT_LAYER_ID_TEXT_COLOR,
182 if (camera_fill_triangle(camera, t, color) < 0) {
188 if (point_layer->state == POINT_LAYER_EDIT_ID) {
189 /* TODO(#855): PointLayer edit field is not scaled on zoom */
190 if (edit_field_render_world(
191 point_layer->edit_field,
193 positions[point_layer->selected]) < 0) {
198 if (active && color_picker_render(&point_layer->color_picker, camera) < 0) {
207 int point_layer_element_at(const PointLayer *point_layer,
210 trace_assert(point_layer);
212 int n = (int) dynarray_count(point_layer->positions);
213 Point *positions = dynarray_data(point_layer->positions);
215 for (int i = 0; i < n; ++i) {
216 if (vec_length(vec_sub(positions[i], position)) < POINT_LAYER_ELEMENT_RADIUS) {
225 int point_layer_add_element(PointLayer *point_layer,
229 trace_assert(point_layer);
231 char id[ID_MAX_SIZE];
232 for (size_t i = 0; i < ID_MAX_SIZE - 1; ++i) {
233 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
235 id[ID_MAX_SIZE - 1] = '\0';
237 dynarray_push(point_layer->positions, &position);
238 dynarray_push(point_layer->colors, &color);
239 dynarray_push(point_layer->ids, id);
245 void point_layer_delete_nth_element(PointLayer *point_layer,
248 trace_assert(point_layer);
249 dynarray_delete_at(point_layer->positions, i);
250 dynarray_delete_at(point_layer->colors, i);
251 dynarray_delete_at(point_layer->ids, i);
255 int point_layer_idle_event(PointLayer *point_layer,
256 const SDL_Event *event,
257 const Camera *camera)
259 trace_assert(point_layer);
261 trace_assert(camera);
264 if (color_picker_event(
265 &point_layer->color_picker,
275 switch (event->type) {
276 case SDL_MOUSEBUTTONDOWN: {
277 switch (event->button.button) {
278 case SDL_BUTTON_LEFT: {
279 const Point position = camera_map_screen(camera, event->button.x, event->button.y);
280 const Color color = color_picker_rgba(&point_layer->color_picker);
282 point_layer->selected = point_layer_element_at(
283 point_layer, position);
285 if (point_layer->selected < 0) {
286 point_layer_add_element(point_layer, position, color);
288 point_layer->state = POINT_LAYER_MOVE;
295 switch (event->key.keysym.sym) {
297 if (0 <= point_layer->selected && point_layer->selected < (int) dynarray_count(point_layer->positions)) {
298 point_layer_delete_nth_element(point_layer, (size_t)point_layer->selected);
299 point_layer->selected = -1;
304 if (point_layer->selected >= 0) {
305 char *ids = dynarray_data(point_layer->ids);
306 point_layer->state = POINT_LAYER_EDIT_ID;
308 point_layer->edit_field,
309 ids + ID_MAX_SIZE * point_layer->selected);
310 SDL_StartTextInput();
321 int point_layer_edit_id_event(PointLayer *point_layer,
322 const SDL_Event *event,
323 const Camera *camera)
325 trace_assert(point_layer);
327 trace_assert(camera);
329 switch (event->type) {
331 switch(event->key.keysym.sym) {
333 char *ids = dynarray_data(point_layer->ids);
334 const char *text = edit_field_as_text(point_layer->edit_field);
335 size_t n = max_size_t(strlen(text), ID_MAX_SIZE - 1);
336 memcpy(ids + point_layer->selected * ID_MAX_SIZE, text, n);
337 *(ids + point_layer->selected * ID_MAX_SIZE + n) = '\0';
338 point_layer->state = POINT_LAYER_IDLE;
344 point_layer->state = POINT_LAYER_IDLE;
352 return edit_field_event(point_layer->edit_field, event);
356 int point_layer_move_event(PointLayer *point_layer,
357 const SDL_Event *event,
358 const Camera *camera)
360 trace_assert(point_layer);
362 trace_assert(camera);
363 trace_assert(point_layer->selected >= 0);
365 switch (event->type) {
366 case SDL_MOUSEBUTTONUP: {
367 switch (event->button.button) {
368 case SDL_BUTTON_LEFT: {
369 point_layer->state = POINT_LAYER_IDLE;
374 case SDL_MOUSEMOTION: {
375 Point *positions = dynarray_data(point_layer->positions);
376 positions[point_layer->selected] =
377 camera_map_screen(camera, event->motion.x, event->motion.y);
384 int point_layer_event(PointLayer *point_layer,
385 const SDL_Event *event,
386 const Camera *camera)
388 trace_assert(point_layer);
390 trace_assert(camera);
392 switch (point_layer->state) {
393 case POINT_LAYER_IDLE:
394 return point_layer_idle_event(point_layer, event, camera);
396 case POINT_LAYER_EDIT_ID:
397 return point_layer_edit_id_event(point_layer, event, camera);
399 case POINT_LAYER_MOVE:
400 return point_layer_move_event(point_layer, event, camera);
406 size_t point_layer_count(const PointLayer *point_layer)
408 trace_assert(point_layer);
409 return dynarray_count(point_layer->positions);
412 const Point *point_layer_positions(const PointLayer *point_layer)
414 trace_assert(point_layer);
415 return dynarray_data(point_layer->positions);
418 const Color *point_layer_colors(const PointLayer *point_layer)
420 trace_assert(point_layer);
421 return dynarray_data(point_layer->colors);
424 const char *point_layer_ids(const PointLayer *point_layer)
426 trace_assert(point_layer);
427 return dynarray_data(point_layer->ids);
430 int point_layer_dump_stream(const PointLayer *point_layer,
433 trace_assert(point_layer);
434 trace_assert(filedump);
436 size_t n = dynarray_count(point_layer->ids);
437 char *ids = dynarray_data(point_layer->ids);
438 Point *positions = dynarray_data(point_layer->positions);
439 Color *colors = dynarray_data(point_layer->colors);
441 fprintf(filedump, "%zd\n", n);
442 for (size_t i = 0; i < n; ++i) {
443 fprintf(filedump, "%s %f %f ",
444 ids + ID_MAX_SIZE * i,
445 positions[i].x, positions[i].y);
446 color_hex_to_stream(colors[i], filedump);
447 fprintf(filedump, "\n");