]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/rect_layer.c
Add TODO(#886)
[nothing.git] / src / game / level / level_editor / rect_layer.c
1 #include "game/camera.h"
2 #include "system/lt.h"
3 #include "system/stacktrace.h"
4 #include "system/nth_alloc.h"
5 #include "system/log.h"
6 #include "math/rect.h"
7 #include "color.h"
8 #include "rect_layer.h"
9 #include "dynarray.h"
10 #include "system/line_stream.h"
11 #include "proto_rect.h"
12 #include "color_picker.h"
13 #include "system/str.h"
14
15 #define RECT_LAYER_ID_MAX_SIZE 36
16
17 /* TODO(#886): RectLayer does not allow to modify ids of Rects */
18 struct RectLayer {
19     Lt *lt;
20     Dynarray *ids;
21     Dynarray *rects;
22     Dynarray *colors;
23     ProtoRect proto_rect;
24     ColorPicker color_picker;
25 };
26
27 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
28 {
29     LayerPtr layer = {
30         .type = LAYER_RECT,
31         .ptr = rect_layer
32     };
33     return layer;
34 }
35
36 RectLayer *create_rect_layer(void)
37 {
38     Lt *lt = create_lt();
39
40     RectLayer *layer = PUSH_LT(lt, nth_calloc(1, sizeof(RectLayer)), free);
41     if (layer == NULL) {
42         RETURN_LT(lt, NULL);
43     }
44     layer->lt = lt;
45
46     layer->ids = PUSH_LT(
47         lt,
48         create_dynarray(sizeof(char) * RECT_LAYER_ID_MAX_SIZE),
49         destroy_dynarray);
50     if (layer->ids == NULL) {
51         RETURN_LT(lt, NULL);
52     }
53
54     layer->rects = PUSH_LT(
55         lt,
56         create_dynarray(sizeof(Rect)),
57         destroy_dynarray);
58     if (layer->rects == NULL) {
59         RETURN_LT(lt, NULL);
60     }
61
62     layer->colors = PUSH_LT(
63         lt,
64         create_dynarray(sizeof(Color)),
65         destroy_dynarray);
66     if (layer->colors == NULL) {
67         RETURN_LT(lt, NULL);
68     }
69
70     layer->color_picker.color = rgba(1.0f, 0.0f, 0.0f, 1.0f);
71     layer->proto_rect.color_current = &layer->color_picker.color;
72     layer->proto_rect.layer_current = layer;
73
74     return layer;
75 }
76
77 RectLayer *create_rect_layer_from_line_stream(LineStream *line_stream)
78 {
79     trace_assert(line_stream);
80
81     RectLayer *layer = create_rect_layer();
82     if (layer == NULL) {
83         return NULL;
84     }
85
86     const char *line = line_stream_next(line_stream);
87     if (line == NULL) {
88         RETURN_LT(layer->lt, NULL);
89     }
90
91     size_t count = 0;
92     if (sscanf(line, "%lu", &count) < 0) {
93         RETURN_LT(layer->lt, NULL);
94     }
95
96     for (size_t i = 0; i < count; ++i) {
97         line = line_stream_next(line_stream);
98         if (line == NULL) {
99             RETURN_LT(layer->lt, NULL);
100         }
101
102         char hex[7];
103         Rect rect;
104         char id[RECT_LAYER_ID_MAX_SIZE];
105
106         if (sscanf(line,
107                    "%"STRINGIFY(RECT_LAYER_ID_MAX_SIZE)"s%f%f%f%f%6s\n",
108                    id,
109                    &rect.x, &rect.y,
110                    &rect.w, &rect.h,
111                    hex) < 0) {
112             RETURN_LT(layer->lt, NULL);
113         }
114
115         Color color = hexstr(hex);
116
117         dynarray_push(layer->rects, &rect);
118         dynarray_push(layer->ids, id);
119         dynarray_push(layer->colors, &color);
120     }
121
122     return layer;
123 }
124
125 void destroy_rect_layer(RectLayer *layer)
126 {
127     trace_assert(layer);
128     RETURN_LT0(layer->lt);
129 }
130
131 int rect_layer_render(const RectLayer *layer, Camera *camera, float fa)
132 {
133     trace_assert(layer);
134     trace_assert(camera);
135
136     const size_t n = dynarray_count(layer->rects);
137     Rect *rects = dynarray_data(layer->rects);
138     Color *colors = dynarray_data(layer->colors);
139
140     for (size_t i = 0; i < n; ++i) {
141         if (camera_fill_rect(
142                 camera,
143                 rects[i],
144                 color_scale(
145                     colors[i],
146                     rgba(1.0f, 1.0f, 1.0f, fa))) < 0) {
147             return -1;
148         }
149     }
150
151     if (proto_rect_render(&layer->proto_rect, camera) < 0) {
152         return -1;
153     }
154
155     if (color_picker_render(&layer->color_picker, camera) < 0) {
156         return -1;
157     }
158
159     return 0;
160 }
161
162 int rect_layer_event(RectLayer *layer, const SDL_Event *event, const Camera *camera)
163 {
164     trace_assert(layer);
165     trace_assert(event);
166
167     switch(event->type) {
168     case SDL_MOUSEBUTTONDOWN:
169     case SDL_MOUSEBUTTONUP: {
170         bool selected = false;
171         if (color_picker_mouse_button(
172                 &layer->color_picker,
173                 &event->button,
174                 &selected) < 0) {
175             return -1;
176         }
177
178         if (!selected && proto_rect_mouse_button(
179                 &layer->proto_rect,
180                 &event->button,
181                 camera) < 0) {
182             return -1;
183         }
184
185     } break;
186
187     case SDL_MOUSEMOTION: {
188         if (proto_rect_mouse_motion(&layer->proto_rect, &event->motion, camera) < 0) {
189             return -1;
190         }
191     } break;
192     }
193
194     return 0;
195 }
196
197 int rect_layer_add_rect(RectLayer *layer, Rect rect, Color color)
198 {
199     trace_assert(layer);
200
201     if (dynarray_push(layer->rects, &rect) < 0) {
202         return -1;
203     }
204
205     if (dynarray_push(layer->colors, &color) < 0) {
206         return -1;
207     }
208
209     char id[RECT_LAYER_ID_MAX_SIZE];
210     for (size_t i = 0; i < RECT_LAYER_ID_MAX_SIZE - 1; ++i) {
211         id[i] = (char) ('a' + rand() % ('z' - 'a' + 1));
212     }
213     id[RECT_LAYER_ID_MAX_SIZE - 1] = '\0';
214
215     if (dynarray_push(layer->ids, id)) {
216         return -1;
217     }
218
219     return 0;
220 }
221
222 int rect_layer_delete_rect_at(RectLayer *layer, Vec position)
223 {
224     trace_assert(layer);
225
226     const size_t n = dynarray_count(layer->rects);
227     Rect *rects = dynarray_data(layer->rects);
228
229     for (size_t i = 0; i < n; ++i) {
230         if (rect_contains_point(rects[i], position)) {
231             dynarray_delete_at(layer->rects, i);
232             dynarray_delete_at(layer->colors, i);
233             return 0;
234         }
235     }
236
237     return 0;
238 }
239
240 size_t rect_layer_count(const RectLayer *layer)
241 {
242     return dynarray_count(layer->rects);
243 }
244
245 const Rect *rect_layer_rects(const RectLayer *layer)
246 {
247     return dynarray_data(layer->rects);
248 }
249
250 const Color *rect_layer_colors(const RectLayer *layer)
251 {
252     return dynarray_data(layer->colors);
253 }
254
255 const char *rect_layer_ids(const RectLayer *layer)
256 {
257     return dynarray_data(layer->ids);
258 }