]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/point_layer.c
Merge pull request #844 from tsoding/841
[nothing.git] / src / game / level / level_editor / point_layer.c
1 #include <SDL2/SDL.h>
2
3 #include "system/stacktrace.h"
4 #include "system/line_stream.h"
5 #include "system/log.h"
6 #include "system/lt.h"
7 #include "system/nth_alloc.h"
8 #include "system/str.h"
9 #include "dynarray.h"
10 #include "game/camera.h"
11 #include "./point_layer.h"
12
13 #define POINT_LAYER_ELEMENT_RADIUS 10.0f
14
15 struct PointLayer
16 {
17     Lt *lt;
18     Dynarray *points;
19     Dynarray *colors;
20     Dynarray *ids;
21     int selected;
22 };
23
24 // TODO(#837): PointLayer does not allow to edit itself
25
26 PointLayer *create_point_layer_from_line_stream(LineStream *line_stream)
27 {
28     trace_assert(line_stream);
29
30     Lt *lt = create_lt();
31     if (lt == NULL) {
32         return NULL;
33     }
34
35     PointLayer *point_layer = PUSH_LT(lt, nth_calloc(1, sizeof(PointLayer)), free);
36     if (point_layer == NULL) {
37         RETURN_LT(lt, NULL);
38     }
39     point_layer->lt = lt;
40
41     point_layer->points = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
42     if (point_layer->points == NULL) {
43         RETURN_LT(lt, NULL);
44     }
45
46     point_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
47     if (point_layer->colors == NULL) {
48         RETURN_LT(lt, NULL);
49     }
50
51     point_layer->ids = PUSH_LT(lt, create_dynarray(sizeof(char) * ID_MAX_SIZE), destroy_dynarray);
52     if (point_layer->ids == NULL) {
53         RETURN_LT(lt, NULL);
54     }
55
56     point_layer->selected = -1;
57
58     size_t count = 0;
59     if (sscanf(
60             line_stream_next(line_stream),
61             "%lu",
62             &count) == EOF) {
63         log_fail("Could not read amount of points");
64         RETURN_LT(lt, NULL);
65     }
66
67     char color_name[7];
68     char id[ID_MAX_SIZE];
69     float x, y;
70     for (size_t i = 0; i < count; ++i) {
71         if (sscanf(
72                 line_stream_next(line_stream),
73                 "%"STRINGIFY(ID_MAX_SIZE)"s%f%f%6s",
74                 id, &x, &y, color_name) < 0) {
75             log_fail("Could not read %dth goal\n", i);
76             RETURN_LT(lt, NULL);
77         }
78         const Color color = hexstr(color_name);
79         const Point point = vec(x, y);
80
81         dynarray_push(point_layer->colors, &color);
82         dynarray_push(point_layer->points, &point);
83         dynarray_push(point_layer->ids, id);
84     }
85
86     return point_layer;
87 }
88
89 void destroy_point_layer(PointLayer *point_layer)
90 {
91     trace_assert(point_layer);
92     RETURN_LT0(point_layer->lt);
93 }
94
95 int point_layer_render(const PointLayer *point_layer,
96                        Camera *camera)
97 {
98     trace_assert(point_layer);
99     trace_assert(camera);
100
101     const int n = (int) dynarray_count(point_layer->points);
102     Point *points = dynarray_data(point_layer->points);
103     Color *colors = dynarray_data(point_layer->colors);
104
105     for (int i = 0; i < n; ++i) {
106         const Triangle t = triangle_mat3x3_product(
107             equilateral_triangle(),
108             mat3x3_product(
109                 trans_mat(points[i].x, points[i].y),
110                 scale_mat(POINT_LAYER_ELEMENT_RADIUS)));
111
112         if (i == point_layer->selected) {
113             const Triangle t0 = triangle_mat3x3_product(
114                 equilateral_triangle(),
115                 mat3x3_product(
116                     trans_mat(points[i].x, points[i].y),
117                     scale_mat(15.0f)));
118
119             if (camera_fill_triangle(camera, t0, color_invert(colors[i])) < 0) {
120                 return -1;
121             }
122         }
123
124         if (camera_fill_triangle(camera, t, colors[i]) < 0) {
125             return -1;
126         }
127     }
128
129     return 0;
130 }
131
132 // TODO(#841): PointLayer does not allow to remove elements
133
134 int point_layer_mouse_button(PointLayer *point_layer,
135                              const SDL_MouseButtonEvent *event,
136                              const Camera *camera,
137                              Color color)
138 {
139     trace_assert(point_layer);
140     trace_assert(event);
141
142     if (event->type == SDL_MOUSEBUTTONDOWN && event->button == SDL_BUTTON_LEFT) {
143         const int n = (int) dynarray_count(point_layer->points);
144         const Point *points = dynarray_data(point_layer->points);
145         const Point point = camera_map_screen(camera, event->x, event->y);
146
147         for (int i = 0; i < n; ++i) {
148             if (vec_length(vec_sub(points[i], point)) < POINT_LAYER_ELEMENT_RADIUS) {
149                 point_layer->selected = i;
150                 return 0;
151             }
152         }
153
154         char id[ID_MAX_SIZE];
155
156         // TODO(#842): PointLayer does not allow to specify an id of a point
157         for (size_t i = 0; i < ID_MAX_SIZE - 1; ++i) {
158             id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
159         }
160
161         dynarray_push(point_layer->points, &point);
162         dynarray_push(point_layer->colors, &color);
163         dynarray_push(point_layer->ids, id);
164     }
165
166     return 0;
167 }
168
169 int point_layer_keyboard(PointLayer *point_layer,
170                          const SDL_KeyboardEvent *event)
171 {
172     trace_assert(point_layer);
173     trace_assert(event);
174
175     if (event->type == SDL_KEYDOWN && event->keysym.sym == SDLK_DELETE) {
176         if (0 <= point_layer->selected && point_layer->selected < (int) dynarray_count(point_layer->points)) {
177             dynarray_delete_at(point_layer->points, (size_t) point_layer->selected);
178             dynarray_delete_at(point_layer->colors, (size_t) point_layer->selected);
179             dynarray_delete_at(point_layer->ids, (size_t) point_layer->selected);
180         }
181
182         point_layer->selected = -1;
183     }
184
185     return 0;
186 }
187
188 size_t point_layer_count(const PointLayer *point_layer)
189 {
190     trace_assert(point_layer);
191     return dynarray_count(point_layer->points);
192 }
193
194 const Point *point_layer_points(const PointLayer *point_layer)
195 {
196     trace_assert(point_layer);
197     return dynarray_data(point_layer->points);
198 }
199
200 const Color *point_layer_colors(const PointLayer *point_layer)
201 {
202     trace_assert(point_layer);
203     return dynarray_data(point_layer->colors);
204 }
205
206 const char *point_layer_ids(const PointLayer *point_layer)
207 {
208     trace_assert(point_layer);
209     return dynarray_data(point_layer->ids);
210 }