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
31 PointLayerState state;
32 Dynarray/*<Point>*/ *positions;
33 Dynarray/*<Color>*/ *colors;
34 Dynarray/*<char[ID_MAX_SIZE]>*/ *ids;
35 Edit_field *edit_field;
37 ColorPicker color_picker;
40 LayerPtr point_layer_as_layer(PointLayer *point_layer)
49 PointLayer *create_point_layer(void)
53 PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free);
54 if (point_layer == NULL) {
59 point_layer->state = POINT_LAYER_IDLE;
61 point_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
62 if (point_layer->positions == NULL) {
66 point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
67 if (point_layer->colors == NULL) {
71 point_layer->ids = PUSH_LT(lt, create_dynarray(sizeof(char) * ID_MAX_SIZE), destroy_dynarray);
72 if (point_layer->ids == NULL) {
76 point_layer->edit_field = PUSH_LT(
79 POINT_LAYER_ID_TEXT_SIZE,
80 POINT_LAYER_ID_TEXT_COLOR),
82 if (point_layer->edit_field == NULL) {
89 PointLayer *create_point_layer_from_line_stream(LineStream *line_stream)
91 trace_assert(line_stream);
93 PointLayer *point_layer = create_point_layer();
97 line_stream_next(line_stream),
100 log_fail("Could not read amount of points");
101 RETURN_LT(point_layer->lt, NULL);
105 char id[ID_MAX_SIZE];
107 for (size_t i = 0; i < count; ++i) {
109 line_stream_next(line_stream),
110 "%"STRINGIFY(ID_MAX_SIZE)"s%f%f%6s",
111 id, &x, &y, color_name) < 0) {
112 log_fail("Could not read %dth goal\n", i);
113 RETURN_LT(point_layer->lt, NULL);
115 const Color color = hexstr(color_name);
116 const Point point = vec(x, y);
118 dynarray_push(point_layer->colors, &color);
119 dynarray_push(point_layer->positions, &point);
120 dynarray_push(point_layer->ids, id);
123 point_layer->selected = -1;
125 point_layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
130 void destroy_point_layer(PointLayer *point_layer)
132 trace_assert(point_layer);
133 RETURN_LT0(point_layer->lt);
136 int point_layer_render(const PointLayer *point_layer,
140 trace_assert(point_layer);
141 trace_assert(camera);
143 const int n = (int) dynarray_count(point_layer->positions);
144 Point *positions = dynarray_data(point_layer->positions);
145 Color *colors = dynarray_data(point_layer->colors);
146 char *ids = dynarray_data(point_layer->ids);
148 for (int i = 0; i < n; ++i) {
149 const Triangle t = triangle_mat3x3_product(
150 equilateral_triangle(),
152 trans_mat(positions[i].x, positions[i].y),
153 scale_mat(POINT_LAYER_ELEMENT_RADIUS)));
155 const Color color = color_scale(
157 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f));
159 if (i == point_layer->selected) {
160 const Triangle t0 = triangle_mat3x3_product(
161 equilateral_triangle(),
163 trans_mat(positions[i].x, positions[i].y),
166 if (camera_fill_triangle(camera, t0, color_invert(color)) < 0) {
170 if (point_layer->state != POINT_LAYER_EDIT_ID &&
173 ids + ID_MAX_SIZE * i,
174 POINT_LAYER_ID_TEXT_SIZE,
175 POINT_LAYER_ID_TEXT_COLOR,
181 if (camera_fill_triangle(camera, t, color) < 0) {
187 if (point_layer->state == POINT_LAYER_EDIT_ID) {
188 if (edit_field_render_world(
189 point_layer->edit_field,
191 positions[point_layer->selected]) < 0) {
196 if (active && color_picker_render(&point_layer->color_picker, camera) < 0) {
205 int point_layer_element_at(const PointLayer *point_layer,
208 trace_assert(point_layer);
210 int n = (int) dynarray_count(point_layer->positions);
211 Point *positions = dynarray_data(point_layer->positions);
213 for (int i = 0; i < n; ++i) {
214 if (vec_length(vec_sub(positions[i], position)) < POINT_LAYER_ELEMENT_RADIUS) {
223 int point_layer_add_element(PointLayer *point_layer,
227 trace_assert(point_layer);
229 char id[ID_MAX_SIZE];
230 for (size_t i = 0; i < ID_MAX_SIZE - 1; ++i) {
231 id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
233 id[ID_MAX_SIZE - 1] = '\0';
235 dynarray_push(point_layer->positions, &position);
236 dynarray_push(point_layer->colors, &color);
237 dynarray_push(point_layer->ids, id);
243 void point_layer_delete_nth_element(PointLayer *point_layer,
246 trace_assert(point_layer);
247 dynarray_delete_at(point_layer->positions, i);
248 dynarray_delete_at(point_layer->colors, i);
249 dynarray_delete_at(point_layer->ids, i);
253 int point_layer_idle_event(PointLayer *point_layer,
254 const SDL_Event *event,
255 const Camera *camera)
257 trace_assert(point_layer);
259 trace_assert(camera);
262 if (color_picker_event(
263 &point_layer->color_picker,
270 if (point_layer->selected >= 0) {
271 Color *colors = dynarray_data(point_layer->colors);
272 colors[point_layer->selected] =
273 color_picker_rgba(&point_layer->color_picker);
279 switch (event->type) {
280 case SDL_MOUSEBUTTONDOWN: {
281 switch (event->button.button) {
282 case SDL_BUTTON_LEFT: {
283 const Point position = camera_map_screen(camera, event->button.x, event->button.y);
285 point_layer->selected = point_layer_element_at(
286 point_layer, position);
288 if (point_layer->selected < 0) {
289 point_layer_add_element(
290 point_layer, position, color_picker_rgba(&point_layer->color_picker));
292 Color *colors = dynarray_data(point_layer->colors);
293 point_layer->state = POINT_LAYER_MOVE;
294 point_layer->color_picker =
295 create_color_picker_from_rgba(colors[point_layer->selected]);
302 switch (event->key.keysym.sym) {
304 if (0 <= point_layer->selected && point_layer->selected < (int) dynarray_count(point_layer->positions)) {
305 point_layer_delete_nth_element(point_layer, (size_t)point_layer->selected);
306 point_layer->selected = -1;
311 if (point_layer->selected >= 0) {
312 char *ids = dynarray_data(point_layer->ids);
313 point_layer->state = POINT_LAYER_EDIT_ID;
315 point_layer->edit_field,
316 ids + ID_MAX_SIZE * point_layer->selected);
317 SDL_StartTextInput();
328 int point_layer_edit_id_event(PointLayer *point_layer,
329 const SDL_Event *event,
330 const Camera *camera)
332 trace_assert(point_layer);
334 trace_assert(camera);
336 switch (event->type) {
338 switch(event->key.keysym.sym) {
340 char *ids = dynarray_data(point_layer->ids);
341 const char *text = edit_field_as_text(point_layer->edit_field);
342 size_t n = max_size_t(strlen(text), ID_MAX_SIZE - 1);
343 memcpy(ids + point_layer->selected * ID_MAX_SIZE, text, n);
344 *(ids + point_layer->selected * ID_MAX_SIZE + n) = '\0';
345 point_layer->state = POINT_LAYER_IDLE;
351 point_layer->state = POINT_LAYER_IDLE;
359 return edit_field_event(point_layer->edit_field, event);
363 int point_layer_move_event(PointLayer *point_layer,
364 const SDL_Event *event,
365 const Camera *camera)
367 trace_assert(point_layer);
369 trace_assert(camera);
370 trace_assert(point_layer->selected >= 0);
372 switch (event->type) {
373 case SDL_MOUSEBUTTONUP: {
374 switch (event->button.button) {
375 case SDL_BUTTON_LEFT: {
376 point_layer->state = POINT_LAYER_IDLE;
381 case SDL_MOUSEMOTION: {
382 Point *positions = dynarray_data(point_layer->positions);
383 positions[point_layer->selected] =
384 camera_map_screen(camera, event->motion.x, event->motion.y);
391 int point_layer_event(PointLayer *point_layer,
392 const SDL_Event *event,
393 const Camera *camera)
395 trace_assert(point_layer);
397 trace_assert(camera);
399 switch (point_layer->state) {
400 case POINT_LAYER_IDLE:
401 return point_layer_idle_event(point_layer, event, camera);
403 case POINT_LAYER_EDIT_ID:
404 return point_layer_edit_id_event(point_layer, event, camera);
406 case POINT_LAYER_MOVE:
407 return point_layer_move_event(point_layer, event, camera);
413 size_t point_layer_count(const PointLayer *point_layer)
415 trace_assert(point_layer);
416 return dynarray_count(point_layer->positions);
419 const Point *point_layer_positions(const PointLayer *point_layer)
421 trace_assert(point_layer);
422 return dynarray_data(point_layer->positions);
425 const Color *point_layer_colors(const PointLayer *point_layer)
427 trace_assert(point_layer);
428 return dynarray_data(point_layer->colors);
431 const char *point_layer_ids(const PointLayer *point_layer)
433 trace_assert(point_layer);
434 return dynarray_data(point_layer->ids);
437 int point_layer_dump_stream(const PointLayer *point_layer,
440 trace_assert(point_layer);
441 trace_assert(filedump);
443 size_t n = dynarray_count(point_layer->ids);
444 char *ids = dynarray_data(point_layer->ids);
445 Point *positions = dynarray_data(point_layer->positions);
446 Color *colors = dynarray_data(point_layer->colors);
448 fprintf(filedump, "%zd\n", n);
449 for (size_t i = 0; i < n; ++i) {
450 fprintf(filedump, "%s %f %f ",
451 ids + ID_MAX_SIZE * i,
452 positions[i].x, positions[i].y);
453 color_hex_to_stream(colors[i], filedump);
454 fprintf(filedump, "\n");