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,
272 if (point_layer->selected >= 0) {
273 Color *colors = dynarray_data(point_layer->colors);
274 colors[point_layer->selected] =
275 color_picker_rgba(&point_layer->color_picker);
281 switch (event->type) {
282 case SDL_MOUSEBUTTONDOWN: {
283 switch (event->button.button) {
284 case SDL_BUTTON_LEFT: {
285 const Point position = camera_map_screen(camera, event->button.x, event->button.y);
287 point_layer->selected = point_layer_element_at(
288 point_layer, position);
290 if (point_layer->selected < 0) {
291 point_layer_add_element(
292 point_layer, position, color_picker_rgba(&point_layer->color_picker));
294 Color *colors = dynarray_data(point_layer->colors);
295 point_layer->state = POINT_LAYER_MOVE;
296 point_layer->color_picker =
297 create_color_picker_from_rgba(colors[point_layer->selected]);
304 switch (event->key.keysym.sym) {
306 if (0 <= point_layer->selected && point_layer->selected < (int) dynarray_count(point_layer->positions)) {
307 point_layer_delete_nth_element(point_layer, (size_t)point_layer->selected);
308 point_layer->selected = -1;
313 if (point_layer->selected >= 0) {
314 char *ids = dynarray_data(point_layer->ids);
315 point_layer->state = POINT_LAYER_EDIT_ID;
317 point_layer->edit_field,
318 ids + ID_MAX_SIZE * point_layer->selected);
319 SDL_StartTextInput();
330 int point_layer_edit_id_event(PointLayer *point_layer,
331 const SDL_Event *event,
332 const Camera *camera)
334 trace_assert(point_layer);
336 trace_assert(camera);
338 switch (event->type) {
340 switch(event->key.keysym.sym) {
342 char *ids = dynarray_data(point_layer->ids);
343 const char *text = edit_field_as_text(point_layer->edit_field);
344 size_t n = max_size_t(strlen(text), ID_MAX_SIZE - 1);
345 memcpy(ids + point_layer->selected * ID_MAX_SIZE, text, n);
346 *(ids + point_layer->selected * ID_MAX_SIZE + n) = '\0';
347 point_layer->state = POINT_LAYER_IDLE;
353 point_layer->state = POINT_LAYER_IDLE;
361 return edit_field_event(point_layer->edit_field, event);
365 int point_layer_move_event(PointLayer *point_layer,
366 const SDL_Event *event,
367 const Camera *camera)
369 trace_assert(point_layer);
371 trace_assert(camera);
372 trace_assert(point_layer->selected >= 0);
374 switch (event->type) {
375 case SDL_MOUSEBUTTONUP: {
376 switch (event->button.button) {
377 case SDL_BUTTON_LEFT: {
378 point_layer->state = POINT_LAYER_IDLE;
383 case SDL_MOUSEMOTION: {
384 Point *positions = dynarray_data(point_layer->positions);
385 positions[point_layer->selected] =
386 camera_map_screen(camera, event->motion.x, event->motion.y);
393 int point_layer_event(PointLayer *point_layer,
394 const SDL_Event *event,
395 const Camera *camera)
397 trace_assert(point_layer);
399 trace_assert(camera);
401 switch (point_layer->state) {
402 case POINT_LAYER_IDLE:
403 return point_layer_idle_event(point_layer, event, camera);
405 case POINT_LAYER_EDIT_ID:
406 return point_layer_edit_id_event(point_layer, event, camera);
408 case POINT_LAYER_MOVE:
409 return point_layer_move_event(point_layer, event, camera);
415 size_t point_layer_count(const PointLayer *point_layer)
417 trace_assert(point_layer);
418 return dynarray_count(point_layer->positions);
421 const Point *point_layer_positions(const PointLayer *point_layer)
423 trace_assert(point_layer);
424 return dynarray_data(point_layer->positions);
427 const Color *point_layer_colors(const PointLayer *point_layer)
429 trace_assert(point_layer);
430 return dynarray_data(point_layer->colors);
433 const char *point_layer_ids(const PointLayer *point_layer)
435 trace_assert(point_layer);
436 return dynarray_data(point_layer->ids);
439 int point_layer_dump_stream(const PointLayer *point_layer,
442 trace_assert(point_layer);
443 trace_assert(filedump);
445 size_t n = dynarray_count(point_layer->ids);
446 char *ids = dynarray_data(point_layer->ids);
447 Point *positions = dynarray_data(point_layer->positions);
448 Color *colors = dynarray_data(point_layer->colors);
450 fprintf(filedump, "%zd\n", n);
451 for (size_t i = 0; i < n; ++i) {
452 fprintf(filedump, "%s %f %f ",
453 ids + ID_MAX_SIZE * i,
454 positions[i].x, positions[i].y);
455 color_hex_to_stream(colors[i], filedump);
456 fprintf(filedump, "\n");