5 #include "system/line_stream.h"
6 #include "system/stacktrace.h"
7 #include "system/nth_alloc.h"
9 #include "system/str.h"
10 #include "system/log.h"
12 #include "label_layer.h"
15 #include "game/camera.h"
16 #include "color_picker.h"
17 #include "ui/edit_field.h"
18 #include "math/extrema.h"
21 #define LABEL_LAYER_SELECTION_THICCNESS 5.0f
23 // TODO(#1139): Label Layer does not support snapping
28 LABEL_LAYER_EDIT_TEXT,
33 static int label_clipboard = 0;
34 static char label_clipboard_text[LABEL_LAYER_TEXT_MAX_SIZE];
35 static Color label_clipboard_color;
39 LabelLayerState state;
45 ColorPicker color_picker;
47 Edit_field *edit_field;
51 const char *id_name_prefix;
64 char id[LABEL_LAYER_ID_MAX_SIZE];
67 char text[LABEL_LAYER_TEXT_MAX_SIZE];
73 LabelUndoContext create_label_undo_swap_context(LabelLayer *label_layer,
74 size_t index, size_t index2)
76 trace_assert(label_layer);
77 trace_assert(index < label_layer->positions.count);
78 trace_assert(index2 < label_layer->positions.count);
80 LabelUndoContext undo_context;
81 undo_context.type = LABEL_UNDO_SWAP;
82 undo_context.layer = label_layer;
83 undo_context.index = index;
84 undo_context.index2 = index2;
89 LabelUndoContext create_label_undo_context(LabelLayer *label_layer, LabelUndoType type)
91 trace_assert(label_layer);
92 trace_assert(type != LABEL_UNDO_SWAP);
94 LabelUndoContext undo_context;
96 size_t index = type == LABEL_UNDO_ADD
97 ? label_layer->positions.count - 1
98 : (size_t)label_layer->selection;
100 undo_context.type = type;
101 undo_context.layer = label_layer;
102 dynarray_copy_to(&label_layer->ids, &undo_context.id, index);
103 dynarray_copy_to(&label_layer->positions, &undo_context.position, index);
104 dynarray_copy_to(&label_layer->colors, &undo_context.color, index);
105 dynarray_copy_to(&label_layer->texts, &undo_context.text, index);
106 undo_context.index = index;
112 void label_layer_undo(void *context, size_t context_size)
114 trace_assert(context);
115 trace_assert(sizeof(LabelUndoContext) == context_size);
117 LabelUndoContext *undo_context = context;
118 LabelLayer *label_layer = undo_context->layer;
120 switch (undo_context->type) {
121 case LABEL_UNDO_ADD: {
122 dynarray_delete_at(&label_layer->ids, undo_context->index);
123 dynarray_delete_at(&label_layer->positions, undo_context->index);
124 dynarray_delete_at(&label_layer->colors, undo_context->index);
125 dynarray_delete_at(&label_layer->texts, undo_context->index);
128 case LABEL_UNDO_DELETE: {
129 dynarray_insert_before(&label_layer->ids, undo_context->index, &undo_context->id);
130 dynarray_insert_before(&label_layer->positions, undo_context->index, &undo_context->position);
131 dynarray_insert_before(&label_layer->colors, undo_context->index, &undo_context->color);
132 dynarray_insert_before(&label_layer->texts, undo_context->index, &undo_context->text);
135 case LABEL_UNDO_UPDATE: {
136 dynarray_replace_at(&label_layer->ids, undo_context->index, &undo_context->id);
137 dynarray_replace_at(&label_layer->positions, undo_context->index, &undo_context->position);
138 dynarray_replace_at(&label_layer->colors, undo_context->index, &undo_context->color);
139 dynarray_replace_at(&label_layer->texts, undo_context->index, &undo_context->text);
142 case LABEL_UNDO_SWAP: {
143 dynarray_swap(&label_layer->ids, undo_context->index, undo_context->index2);
144 dynarray_swap(&label_layer->positions, undo_context->index, undo_context->index2);
145 dynarray_swap(&label_layer->colors, undo_context->index, undo_context->index2);
146 dynarray_swap(&label_layer->texts, undo_context->index, undo_context->index2);
151 #define LABEL_UNDO_PUSH(HISTORY, CONTEXT) \
153 LabelUndoContext context = (CONTEXT); \
162 LayerPtr label_layer_as_layer(LabelLayer *label_layer)
171 LabelLayer *create_label_layer(const char *id_name_prefix)
173 Lt *lt = create_lt();
175 LabelLayer *label_layer = PUSH_LT(
176 lt, nth_calloc(1, sizeof(LabelLayer)), free);
177 if (label_layer == NULL) {
180 label_layer->lt = lt;
182 label_layer->ids = create_dynarray(sizeof(char) * LABEL_LAYER_ID_MAX_SIZE);
183 label_layer->positions = create_dynarray(sizeof(Vec2f));
184 label_layer->colors = create_dynarray(sizeof(Color));
185 label_layer->texts = create_dynarray(sizeof(char) * LABEL_LAYER_TEXT_MAX_SIZE);
187 label_layer->color_picker = create_color_picker_from_rgba(COLOR_RED);
188 label_layer->selection = -1;
190 label_layer->edit_field = PUSH_LT(
192 create_edit_field(LABELS_SIZE, COLOR_RED),
194 if (label_layer->edit_field == NULL) {
198 label_layer->id_name_prefix = id_name_prefix;
203 LabelLayer *create_label_layer_from_line_stream(LineStream *line_stream, const char *id_name_prefix)
205 trace_assert(line_stream);
206 LabelLayer *label_layer = create_label_layer(id_name_prefix);
208 if (label_layer == NULL) {
209 RETURN_LT(label_layer->lt, NULL);
212 const char *line = line_stream_next(line_stream);
214 log_fail("Could not read amount of labels\n");
215 RETURN_LT(label_layer->lt, NULL);
219 if (sscanf(line, "%zu", &n) == EOF) {
220 log_fail("Could not parse amount of labels\n");
221 RETURN_LT(label_layer->lt, NULL);
224 for (size_t i = 0; i < n; ++i) {
226 char id[LABEL_LAYER_ID_MAX_SIZE];
229 line = line_stream_next(line_stream);
231 log_fail("Could not read label meta info\n");
232 RETURN_LT(label_layer->lt, NULL);
237 "%"STRINGIFY(LABEL_LAYER_ID_MAX_SIZE)"s%f%f%6s\n",
238 id, &position.x, &position.y, hex) == EOF) {
239 log_fail("Could not parse label meta info\n");
240 RETURN_LT(label_layer->lt, NULL);
243 Color color = hexstr(hex);
245 dynarray_push(&label_layer->ids, id);
246 dynarray_push(&label_layer->positions, &position);
247 dynarray_push(&label_layer->colors, &color);
249 line = line_stream_next(line_stream);
251 log_fail("Could not read label text\n");
254 char label_text[LABEL_LAYER_TEXT_MAX_SIZE] = {0};
255 memcpy(label_text, line, LABEL_LAYER_TEXT_MAX_SIZE - 1);
256 trim_endline(label_text);
257 dynarray_push(&label_layer->texts, &label_text);
263 LabelLayer *chop_label_layer(Memory *memory,
265 const char *id_name_prefix)
267 trace_assert(memory);
269 trace_assert(id_name_prefix);
271 LabelLayer *label_layer = create_label_layer(id_name_prefix);
273 int n = atoi(string_to_cstr(memory, trim(chop_by_delim(input, '\n'))));
274 char id[LABEL_LAYER_ID_MAX_SIZE];
275 char label_text[LABEL_LAYER_TEXT_MAX_SIZE];
276 for (int i = 0; i < n; ++i) {
277 String meta = trim(chop_by_delim(input, '\n'));
279 String string_id = trim(chop_word(&meta));
281 position.x = strtof(string_to_cstr(memory, trim(chop_word(&meta))), NULL);
282 position.y = strtof(string_to_cstr(memory, trim(chop_word(&meta))), NULL);
283 Color color = hexs(trim(chop_word(&meta)));
285 memset(id, 0, LABEL_LAYER_ID_MAX_SIZE);
289 min_size_t(LABEL_LAYER_ID_MAX_SIZE - 1, string_id.count));
291 String label_text_string =
292 trim(chop_by_delim(input, '\n'));
293 memset(label_text, 0, LABEL_LAYER_TEXT_MAX_SIZE);
296 label_text_string.data,
297 min_size_t(LABEL_LAYER_TEXT_MAX_SIZE - 1,
298 label_text_string.count));
300 dynarray_push(&label_layer->ids, id);
301 dynarray_push(&label_layer->positions, &position);
302 dynarray_push(&label_layer->colors, &color);
303 dynarray_push(&label_layer->texts, label_text);
309 void destroy_label_layer(LabelLayer *label_layer)
311 trace_assert(label_layer);
313 free(label_layer->ids.data);
314 free(label_layer->positions.data);
315 free(label_layer->colors.data);
316 free(label_layer->texts.data);
318 destroy_lt(label_layer->lt);
322 Rect boundary_of_element(const LabelLayer *label_layer,
326 trace_assert(i < label_layer->texts.count);
328 char *ids = (char *)label_layer->ids.data;
329 char *texts = (char *)label_layer->texts.data;
331 return rect_boundary2(
332 sprite_font_boundary_box(
335 texts + i * LABEL_LAYER_TEXT_MAX_SIZE),
336 sprite_font_boundary_box(
340 vec(0.0f, FONT_CHAR_HEIGHT),
343 ids + i * LABEL_LAYER_ID_MAX_SIZE));
346 int label_layer_render(const LabelLayer *label_layer,
347 const Camera *camera,
350 trace_assert(label_layer);
351 trace_assert(camera);
353 if (active && color_picker_render(&label_layer->color_picker, camera) < 0) {
357 size_t n = label_layer->ids.count;
358 char *ids = (char *)label_layer->ids.data;
359 Vec2f *positions = (Vec2f *)label_layer->positions.data;
360 Color *colors = (Color *)label_layer->colors.data;
361 char *texts = (char *)label_layer->texts.data;
363 /* TODO(#891): LabelLayer doesn't show the final position of Label after the animation */
364 for (size_t i = 0; i < n; ++i) {
365 const Color color = label_layer->state == LABEL_LAYER_RECOLOR && label_layer->selection == (int) i
366 ? label_layer->inter_color
369 const Vec2f position =
370 label_layer->state == LABEL_LAYER_MOVE && label_layer->selection == (int) i
371 ? label_layer->inter_position
375 if (label_layer->state == LABEL_LAYER_EDIT_TEXT && label_layer->selection == (int) i) {
376 if (edit_field_render_world(
377 label_layer->edit_field,
383 if (camera_render_text(
385 texts + i * LABEL_LAYER_TEXT_MAX_SIZE,
389 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f)),
396 if (label_layer->state == LABEL_LAYER_EDIT_ID && label_layer->selection == (int)i) {
397 if (edit_field_render_world(
398 label_layer->edit_field,
403 vec(0.0f, FONT_CHAR_HEIGHT),
404 LABELS_SIZE))) < 0) {
408 if (camera_render_text(
410 ids + i * LABEL_LAYER_ID_MAX_SIZE,
414 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f)),
418 vec(0.0f, FONT_CHAR_HEIGHT),
419 LABELS_SIZE))) < 0) {
425 // TODO(#1160): Label Selection has to be internal (just like in Rect Layer)
426 if (active && label_layer->selection == (int) i) {
435 LABEL_LAYER_SELECTION_THICCNESS * 0.5f);
438 if (camera_draw_thicc_rect_screen(
442 LABEL_LAYER_SELECTION_THICCNESS) < 0) {
453 int label_layer_element_at(LabelLayer *label_layer,
456 trace_assert(label_layer);
458 Vec2f *positions = (Vec2f*)label_layer->positions.data;
460 const int n = (int) label_layer->texts.count;
461 for (int i = n - 1; i >= 0; --i) {
462 if (rect_contains_point(
476 void label_layer_delete_selected_label(LabelLayer *label_layer,
477 UndoHistory *undo_history)
479 trace_assert(label_layer);
480 trace_assert(label_layer->selection >= 0);
482 LABEL_UNDO_PUSH(undo_history, create_label_undo_context(label_layer, LABEL_UNDO_DELETE));
484 dynarray_delete_at(&label_layer->ids, (size_t)label_layer->selection);
485 dynarray_delete_at(&label_layer->positions, (size_t)label_layer->selection);
486 dynarray_delete_at(&label_layer->colors, (size_t)label_layer->selection);
487 dynarray_delete_at(&label_layer->texts, (size_t)label_layer->selection);
489 label_layer->selection = -1;
493 int label_layer_add_label(LabelLayer *label_layer,
497 UndoHistory *undo_history)
499 trace_assert(label_layer);
501 // TODO(#982): id generation code is duplicated in label_layer, point_layer and rect_layer
502 char id[LABEL_LAYER_ID_MAX_SIZE];
503 snprintf(id, LABEL_LAYER_ID_MAX_SIZE, "%s_%d",
504 label_layer->id_name_prefix,
505 label_layer->id_name_counter++);
507 size_t n = label_layer->ids.count;
509 dynarray_push(&label_layer->ids, id);
510 dynarray_push(&label_layer->positions, &position);
511 dynarray_push(&label_layer->colors, &color);
512 dynarray_push_empty(&label_layer->texts);
514 dynarray_pointer_at(&label_layer->texts, n),
516 min_size_t(LABEL_LAYER_ID_MAX_SIZE - 1, strlen(text)));
518 LABEL_UNDO_PUSH(undo_history, create_label_undo_context(label_layer, LABEL_UNDO_ADD));
524 void label_layer_swap_elements(LabelLayer *label_layer,
526 UndoHistory *undo_history)
528 trace_assert(label_layer);
529 trace_assert(undo_history);
530 trace_assert(a < label_layer->positions.count);
531 trace_assert(b < label_layer->positions.count);
533 dynarray_swap(&label_layer->ids, a, b);
534 dynarray_swap(&label_layer->positions, a, b);
535 dynarray_swap(&label_layer->colors, a, b);
536 dynarray_swap(&label_layer->texts, a, b);
538 LABEL_UNDO_PUSH(undo_history, create_label_undo_swap_context(label_layer, a, b));
542 int label_layer_idle_event(LabelLayer *label_layer,
543 const SDL_Event *event,
544 const Camera *camera,
545 UndoHistory *undo_history)
547 trace_assert(label_layer);
549 trace_assert(camera);
553 if (color_picker_event(
554 &label_layer->color_picker,
562 if (label_layer->selection >= 0) {
563 label_layer->state = LABEL_LAYER_RECOLOR;
564 label_layer->inter_color = color_picker_rgba(&label_layer->color_picker);
569 Color *colors = (Color*)label_layer->colors.data;
570 Vec2f *positions = (Vec2f*)label_layer->positions.data;
571 char *ids = (char*)label_layer->ids.data;
572 char *texts = (char*)label_layer->texts.data;
574 switch (event->type) {
575 case SDL_MOUSEBUTTONDOWN: {
576 switch (event->button.button) {
577 case SDL_BUTTON_LEFT: {
578 const Vec2f position = camera_map_screen(
583 const int element = label_layer_element_at(
588 label_layer->move_anchor = vec_sub(position, positions[element]);
589 label_layer->selection = element;
590 label_layer->state = LABEL_LAYER_MOVE;
591 label_layer->inter_position = positions[element];
593 label_layer->color_picker =
594 create_color_picker_from_rgba(colors[element]);
596 label_layer->selection = label_layer_add_label(
600 &label_layer->color_picker),
603 label_layer->state = LABEL_LAYER_EDIT_TEXT;
605 label_layer->edit_field,
606 texts + label_layer->selection * LABEL_LAYER_TEXT_MAX_SIZE);
608 label_layer->edit_field,
610 colors[label_layer->selection]);
611 SDL_StartTextInput();
618 switch (event->key.keysym.sym) {
620 if ((event->key.keysym.mod & KMOD_SHIFT)
621 && (label_layer->selection >= 0)
622 && ((size_t)(label_layer->selection + 1) < label_layer->positions.count)) {
623 label_layer_swap_elements(
625 (size_t) label_layer->selection,
626 (size_t) label_layer->selection + 1,
628 label_layer->selection++;
633 if ((event->key.keysym.mod & KMOD_SHIFT)
634 && (label_layer->selection > 0)
635 && ((size_t) label_layer->selection < label_layer->positions.count)) {
636 label_layer_swap_elements(
638 (size_t) label_layer->selection,
639 (size_t) label_layer->selection - 1,
641 label_layer->selection--;
646 if (label_layer->selection >= 0) {
647 label_layer->state = LABEL_LAYER_EDIT_TEXT;
649 label_layer->edit_field,
650 texts + label_layer->selection * LABEL_LAYER_TEXT_MAX_SIZE);
652 label_layer->edit_field,
654 colors[label_layer->selection]);
655 SDL_StartTextInput();
660 if (label_layer->selection >= 0) {
661 label_layer->state = LABEL_LAYER_EDIT_ID;
663 label_layer->edit_field,
664 ids + label_layer->selection * LABEL_LAYER_ID_MAX_SIZE);
666 label_layer->edit_field,
668 color_invert(colors[label_layer->selection]));
669 SDL_StartTextInput();
674 if (label_layer->selection >= 0) {
675 label_layer_delete_selected_label(
678 label_layer->selection = -1;
683 if ((event->key.keysym.mod & KMOD_LCTRL) && label_layer->selection >= 0) {
685 dynarray_copy_to(&label_layer->texts, label_clipboard_text, (size_t)label_layer->selection);
686 dynarray_copy_to(&label_layer->colors, &label_clipboard_color, (size_t)label_layer->selection);
691 if ((event->key.keysym.mod & KMOD_LCTRL) && label_clipboard) {
693 SDL_GetMouseState(&x, &y);
694 Vec2f position = camera_map_screen(camera, x, y);
696 label_layer_add_label(
699 label_clipboard_color,
700 label_clipboard_text,
712 void snap_inter_position(LabelLayer *label_layer, float snap_threshold)
714 trace_assert(label_layer);
715 trace_assert(label_layer->selection >= 0);
716 trace_assert(label_layer->state == LABEL_LAYER_MOVE);
718 const size_t n = label_layer->positions.count;
719 Vec2f *positions = (Vec2f*)label_layer->positions.data;
721 Rect a = boundary_of_element(
723 (size_t) label_layer->selection,
724 label_layer->inter_position);
726 for (size_t i = 0; i < n; ++i) {
727 if (i == (size_t) label_layer->selection) continue;
729 const Rect b = boundary_of_element(label_layer, i, positions[i]);
731 if (segment_overlap(vec(a.x, a.x + a.w), vec(b.x, b.x + b.w))) {
732 snap_seg2seg(&label_layer->inter_position.y,
733 b.y, a.h, b.h, snap_threshold);
736 if (segment_overlap(vec(a.y, a.y + a.h), vec(b.y, b.y + b.h))) {
737 snap_seg2seg(&label_layer->inter_position.x,
738 b.x, a.w, b.w, snap_threshold);
744 int label_layer_move_event(LabelLayer *label_layer,
745 const SDL_Event *event,
746 const Camera *camera,
747 UndoHistory *undo_history)
749 trace_assert(label_layer);
751 trace_assert(camera);
752 trace_assert(label_layer->selection >= 0);
754 Vec2f *positions = (Vec2f*)label_layer->positions.data;
756 switch (event->type) {
757 case SDL_MOUSEMOTION: {
758 const Uint8 *state = SDL_GetKeyboardState(NULL);
759 const Vec2f mouse_pos = vec_sub(
764 label_layer->move_anchor);
766 if (!(state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL])) {
767 label_layer->inter_position = mouse_pos;
769 const Vec2f label_pos = positions[label_layer->selection];
771 const float dx = fabsf(label_pos.x - mouse_pos.x);
772 const float dy = fabsf(label_pos.y - mouse_pos.y);
775 label_layer->inter_position = vec(mouse_pos.x, label_pos.y);
777 label_layer->inter_position = vec(label_pos.x, mouse_pos.y);
781 snap_inter_position(label_layer, SNAPPING_THRESHOLD);
784 case SDL_MOUSEBUTTONUP: {
785 switch (event->button.button) {
786 case SDL_BUTTON_LEFT: {
787 const float distance = vec_length(
788 vec_sub(label_layer->inter_position,
789 positions[label_layer->selection]));
791 if (distance > 1e-6) {
792 LABEL_UNDO_PUSH(undo_history, create_label_undo_context(label_layer, LABEL_UNDO_UPDATE));
795 &label_layer->positions,
796 (size_t)label_layer->selection,
797 &label_layer->inter_position);
800 label_layer->state = LABEL_LAYER_IDLE;
810 int label_layer_edit_text_event(LabelLayer *label_layer,
811 const SDL_Event *event,
812 const Camera *camera,
813 UndoHistory *undo_history)
815 trace_assert(label_layer);
817 trace_assert(camera);
818 trace_assert(label_layer->selection >= 0);
820 switch (event->type) {
822 switch (event->key.keysym.sym) {
824 LABEL_UNDO_PUSH(undo_history, create_label_undo_context(label_layer, LABEL_UNDO_UPDATE));
827 (char*)label_layer->texts.data + label_layer->selection * LABEL_LAYER_TEXT_MAX_SIZE;
828 memset(text, 0, LABEL_LAYER_TEXT_MAX_SIZE);
829 memcpy(text, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_TEXT_MAX_SIZE - 1);
830 label_layer->state = LABEL_LAYER_IDLE;
836 label_layer->state = LABEL_LAYER_IDLE;
844 return edit_field_event(label_layer->edit_field, event);
848 int label_layer_edit_id_event(LabelLayer *label_layer,
849 const SDL_Event *event,
850 const Camera *camera,
851 UndoHistory *undo_history)
853 trace_assert(label_layer);
855 trace_assert(camera);
856 trace_assert(undo_history);
857 trace_assert(label_layer->selection >= 0);
859 switch (event->type) {
861 switch (event->key.keysym.sym) {
863 LABEL_UNDO_PUSH(undo_history, create_label_undo_context(label_layer, LABEL_UNDO_UPDATE));
866 (char*)label_layer->ids.data + label_layer->selection * LABEL_LAYER_ID_MAX_SIZE;
867 memset(id, 0, LABEL_LAYER_ID_MAX_SIZE);
868 memcpy(id, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_ID_MAX_SIZE - 1);
869 label_layer->state = LABEL_LAYER_IDLE;
875 label_layer->state = LABEL_LAYER_IDLE;
883 return edit_field_event(label_layer->edit_field, event);
887 int label_layer_recolor_event(LabelLayer *label_layer,
888 const SDL_Event *event,
889 const Camera *camera,
890 UndoHistory *undo_history)
892 trace_assert(label_layer);
894 trace_assert(camera);
895 trace_assert(undo_history);
896 trace_assert(label_layer->selection >= 0);
900 if (color_picker_event(
901 &label_layer->color_picker,
909 label_layer->inter_color =
910 color_picker_rgba(&label_layer->color_picker);
912 if (!color_picker_drag(&label_layer->color_picker)) {
913 LABEL_UNDO_PUSH(undo_history, create_label_undo_context(label_layer, LABEL_UNDO_UPDATE));
916 &label_layer->colors,
917 (size_t) label_layer->selection,
918 &label_layer->inter_color);
919 label_layer->state = LABEL_LAYER_IDLE;
926 int label_layer_event(LabelLayer *label_layer,
927 const SDL_Event *event,
928 const Camera *camera,
929 UndoHistory *undo_history)
931 trace_assert(label_layer);
933 trace_assert(camera);
934 trace_assert(undo_history);
936 switch (label_layer->state) {
937 case LABEL_LAYER_IDLE:
938 return label_layer_idle_event(label_layer, event, camera, undo_history);
940 case LABEL_LAYER_MOVE:
941 return label_layer_move_event(label_layer, event, camera, undo_history);
943 case LABEL_LAYER_EDIT_TEXT:
944 return label_layer_edit_text_event(label_layer, event, camera, undo_history);
946 case LABEL_LAYER_EDIT_ID:
947 return label_layer_edit_id_event(label_layer, event, camera, undo_history);
949 case LABEL_LAYER_RECOLOR:
950 return label_layer_recolor_event(label_layer, event, camera, undo_history);
956 size_t label_layer_count(const LabelLayer *label_layer)
958 return label_layer->ids.count;
961 char *label_layer_ids(const LabelLayer *label_layer)
963 return (char *)label_layer->ids.data;
966 Vec2f *label_layer_positions(const LabelLayer *label_layer)
968 return (Vec2f *)label_layer->positions.data;
971 Color *label_layer_colors(const LabelLayer *label_layer)
973 return (Color *)label_layer->colors.data;
976 char *labels_layer_texts(const LabelLayer *label_layer)
978 return (char *)label_layer->texts.data;
981 int label_layer_dump_stream(const LabelLayer *label_layer, FILE *filedump)
983 trace_assert(label_layer);
984 trace_assert(filedump);
986 size_t n = label_layer->ids.count;
987 char *ids = (char *)label_layer->ids.data;
988 Vec2f *positions = (Vec2f *)label_layer->positions.data;
989 Color *colors = (Color *)label_layer->colors.data;
990 char *texts = (char *)label_layer->texts.data;
992 fprintf(filedump, "%zd\n", n);
993 for (size_t i = 0; i < n; ++i) {
994 fprintf(filedump, "%s %f %f ",
995 ids + LABEL_LAYER_ID_MAX_SIZE * i,
996 positions[i].x, positions[i].y);
997 color_hex_to_stream(colors[i], filedump);
998 fprintf(filedump, "\n%s\n", texts + i * LABEL_LAYER_TEXT_MAX_SIZE);