]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor.c
Merge pull request #844 from tsoding/841
[nothing.git] / src / game / level / level_editor.c
1 #include <stdbool.h>
2
3 #include "game/camera.h"
4 #include "game/level/boxes.h"
5 #include "game/level/level_editor/proto_rect.h"
6 #include "game/level/level_editor/color_picker.h"
7 #include "game/level/level_editor/layer.h"
8 #include "game/level/level_editor/point_layer.h"
9 #include "game/level/level_editor/layer_picker.h"
10 #include "system/stacktrace.h"
11 #include "system/nth_alloc.h"
12 #include "system/lt.h"
13
14 #include "level_editor.h"
15
16 struct LevelEditor
17 {
18     Lt *lt;
19     Vec camera_position;
20     float camera_scale;
21     LayerPicker layer_picker;
22     ColorPicker color_picker;
23     ProtoRect proto_rect;
24
25     RectLayer *boxes_layer;
26     RectLayer *platforms_layer;
27     RectLayer *back_platforms_layer;
28     PointLayer *goals_layer;
29
30     RectLayer *current_rect_layer;
31     PointLayer *current_point_layer;
32     // TODO(#823): LevelEditor does not allow to switch the current layer
33     bool drag;
34 };
35
36 LevelEditor *create_level_editor(RectLayer *boxes_layer,
37                                  RectLayer *platforms_layer,
38                                  RectLayer *back_platforms_layer,
39                                  PointLayer *goals_layer)
40 {
41     trace_assert(boxes_layer);
42     trace_assert(platforms_layer);
43     trace_assert(back_platforms_layer);
44     trace_assert(goals_layer);
45
46     Lt *lt = create_lt();
47     if (lt == NULL) {
48         return NULL;
49     }
50
51     LevelEditor *level_editor = PUSH_LT(lt, nth_calloc(1, sizeof(LevelEditor)), free);
52     if (level_editor == NULL) {
53         RETURN_LT(lt, NULL);
54     }
55     level_editor->lt = lt;
56
57     level_editor->camera_position = vec(0.0f, 0.0f);
58     level_editor->camera_scale = 1.0f;
59
60     level_editor->boxes_layer = PUSH_LT(lt, boxes_layer, destroy_rect_layer);
61     level_editor->platforms_layer = PUSH_LT(lt, platforms_layer, destroy_rect_layer);
62     level_editor->back_platforms_layer = PUSH_LT(lt, back_platforms_layer, destroy_rect_layer);
63     level_editor->goals_layer = PUSH_LT(lt, goals_layer, destroy_point_layer);
64     level_editor->current_rect_layer = boxes_layer;
65     level_editor->current_point_layer = goals_layer;
66
67     level_editor->color_picker.color = rgba(1.0f, 0.0f, 0.0f, 1.0f);
68     level_editor->layer_picker = LAYER_PICKER_BOXES;
69
70     level_editor->proto_rect.color_current = &level_editor->color_picker.color;
71     level_editor->proto_rect.layer_current = &level_editor->current_rect_layer;
72
73     level_editor->drag = false;
74
75     return level_editor;
76 }
77
78 void destroy_level_editor(LevelEditor *level_editor)
79 {
80     trace_assert(level_editor);
81     RETURN_LT0(level_editor->lt);
82 }
83
84 int level_editor_render(const LevelEditor *level_editor,
85                         Camera *camera)
86 {
87     trace_assert(level_editor);
88     trace_assert(camera);
89
90     if (rect_layer_render(level_editor->back_platforms_layer, camera) < 0) {
91         return -1;
92     }
93
94     if (rect_layer_render(level_editor->boxes_layer, camera) < 0) {
95         return -1;
96     }
97
98     if (rect_layer_render(level_editor->platforms_layer, camera) < 0) {
99         return -1;
100     }
101
102     if (point_layer_render(level_editor->goals_layer, camera) < 0) {
103         return -1;
104     }
105
106     if (proto_rect_render(&level_editor->proto_rect, camera) < 0) {
107         return -1;
108     }
109
110     if (color_picker_render(&level_editor->color_picker, camera) < 0) {
111         return -1;
112     }
113
114     if (layer_picker_render(&level_editor->layer_picker, camera) < 0) {
115         return -1;
116     }
117
118     return 0;
119 }
120
121 int level_editor_update(LevelEditor *level_editor,
122                         float delta_time)
123 {
124     trace_assert(level_editor);
125
126     if (proto_rect_update(&level_editor->proto_rect, delta_time) < 0) {
127         return -1;
128     }
129
130     return 0;
131 }
132
133 int level_editor_event(LevelEditor *level_editor,
134                        const SDL_Event *event,
135                        const Camera *camera)
136 {
137     trace_assert(level_editor);
138     trace_assert(event);
139     trace_assert(camera);
140
141     switch (event->type) {
142     case SDL_KEYDOWN:
143     case SDL_KEYUP: {
144         if (layer_picker_type(&level_editor->layer_picker) == LAYER_TYPE_RECT) {
145             // Nothing
146         } else {
147             if (point_layer_keyboard(
148                     level_editor->current_point_layer,
149                     &event->key) < 0) {
150                 return -1;
151             }
152         }
153     } break;
154
155     case SDL_MOUSEWHEEL: {
156         // TODO(#679): zooming in edit mode is not smooth enough
157         if (event->wheel.y > 0) {
158             level_editor->camera_scale += 0.1f;
159         } else if (event->wheel.y < 0) {
160             level_editor->camera_scale = fmaxf(0.1f, level_editor->camera_scale - 0.1f);
161         }
162     } break;
163
164     case SDL_MOUSEBUTTONUP:
165     case SDL_MOUSEBUTTONDOWN: {
166         bool selected = false;
167         if (color_picker_mouse_button(
168                 &level_editor->color_picker,
169                 &event->button,
170                 &selected) < 0) {
171             return -1;
172         }
173
174         if (layer_picker_mouse_button(
175                 &level_editor->layer_picker,
176                 camera,
177                 &event->button,
178                 &selected) < 0) {
179             return -1;
180         }
181
182         switch (level_editor->layer_picker) {
183         case LAYER_PICKER_BOXES: {
184             level_editor->current_rect_layer = level_editor->boxes_layer;
185         } break;
186         case LAYER_PICKER_PLATFORMS: {
187             level_editor->current_rect_layer = level_editor->platforms_layer;
188         } break;
189         case LAYER_PICKER_BACK_PLATFORMS: {
190             level_editor->current_rect_layer = level_editor->back_platforms_layer;
191         } break;
192         case LAYER_PICKER_GOALS: {
193             level_editor->current_point_layer = level_editor->goals_layer;
194         } break;
195
196         default: {}
197         }
198
199         if (layer_picker_type(&level_editor->layer_picker) == LAYER_TYPE_RECT) {
200             if (!selected && proto_rect_mouse_button(
201                     &level_editor->proto_rect,
202                     &event->button,
203                     camera) < 0) {
204                 return -1;
205             }
206         } else {
207             if (!selected && point_layer_mouse_button(
208                     level_editor->current_point_layer,
209                     &event->button,
210                     camera,
211                     level_editor->color_picker.color) < 0) {
212                 return -1;
213             }
214         }
215
216         if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_MIDDLE) {
217             level_editor->drag = true;
218         }
219
220         if (event->type == SDL_MOUSEBUTTONUP && event->button.button == SDL_BUTTON_MIDDLE) {
221             level_editor->drag = false;
222         }
223     } break;
224
225     case SDL_MOUSEMOTION: {
226         if (level_editor->drag) {
227             const Vec next_position = camera_map_screen(camera, event->motion.x, event->motion.y);
228             const Vec prev_position = camera_map_screen(
229                 camera,
230                 event->motion.x + event->motion.xrel,
231                 event->motion.y + event->motion.yrel);
232
233             vec_add(&level_editor->camera_position,
234                     vec_sub(next_position, prev_position));
235         }
236
237         if (proto_rect_mouse_motion(&level_editor->proto_rect, &event->motion, camera) < 0) {
238             return -1;
239         }
240     } break;
241     }
242
243     return 0;
244 }
245
246 int level_editor_focus_camera(LevelEditor *level_editor,
247                               Camera *camera)
248 {
249     camera_center_at(camera, level_editor->camera_position);
250     camera_scale(camera, level_editor->camera_scale);
251     return 0;
252 }
253
254 const RectLayer *level_editor_boxes(const LevelEditor *level_editor)
255 {
256     return level_editor->boxes_layer;
257 }
258
259 const RectLayer *level_editor_platforms(const LevelEditor *level_editor)
260 {
261     return level_editor->platforms_layer;
262 }
263
264 const RectLayer *level_editor_back_platforms(const LevelEditor *level_editor)
265 {
266     return level_editor->back_platforms_layer;
267 }
268
269 const PointLayer *level_editor_goals_layer(const LevelEditor *level_editor)
270 {
271     return level_editor->goals_layer;
272 }