]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor.c
(#837) rect_rect -> rect
[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_rect_layer;
26     RectLayer *platforms_rect_layer;
27     RectLayer *back_platforms_rect_layer;
28     PointLayer *goals_rect_layer;
29
30     RectLayer *current_rect_layer;
31     PointLayer *current_point_rect_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_rect_layer,
37                                  RectLayer *platforms_rect_layer,
38                                  RectLayer *back_platforms_rect_layer,
39                                  PointLayer *goals_rect_layer)
40 {
41     trace_assert(boxes_rect_layer);
42     trace_assert(platforms_rect_layer);
43     trace_assert(back_platforms_rect_layer);
44     trace_assert(goals_rect_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_rect_layer = PUSH_LT(lt, boxes_rect_layer, destroy_rect_layer);
61     level_editor->platforms_rect_layer = PUSH_LT(lt, platforms_rect_layer, destroy_rect_layer);
62     level_editor->back_platforms_rect_layer = PUSH_LT(lt, back_platforms_rect_layer, destroy_rect_layer);
63     level_editor->goals_rect_layer = PUSH_LT(lt, goals_rect_layer, destroy_point_rect_layer);
64     level_editor->current_rect_layer = boxes_rect_layer;
65     level_editor->current_point_rect_layer = goals_rect_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 (layer_render(level_editor->back_platforms_rect_layer, camera) < 0) {
91         return -1;
92     }
93
94     if (layer_render(level_editor->boxes_rect_layer, camera) < 0) {
95         return -1;
96     }
97
98     if (layer_render(level_editor->platforms_rect_layer, camera) < 0) {
99         return -1;
100     }
101
102     if (proto_rect_render(&level_editor->proto_rect, camera) < 0) {
103         return -1;
104     }
105
106     if (color_picker_render(&level_editor->color_picker, camera) < 0) {
107         return -1;
108     }
109
110     if (layer_picker_render(&level_editor->layer_picker, camera) < 0) {
111         return -1;
112     }
113
114     return 0;
115 }
116
117 int level_editor_update(LevelEditor *level_editor,
118                         float delta_time)
119 {
120     trace_assert(level_editor);
121
122     if (proto_rect_update(&level_editor->proto_rect, delta_time) < 0) {
123         return -1;
124     }
125
126     return 0;
127 }
128
129 int level_editor_event(LevelEditor *level_editor,
130                        const SDL_Event *event,
131                        const Camera *camera)
132 {
133     trace_assert(level_editor);
134     trace_assert(event);
135     trace_assert(camera);
136
137     switch (event->type) {
138     case SDL_MOUSEWHEEL: {
139         // TODO(#679): zooming in edit mode is not smooth enough
140         if (event->wheel.y > 0) {
141             level_editor->camera_scale += 0.1f;
142         } else if (event->wheel.y < 0) {
143             level_editor->camera_scale = fmaxf(0.1f, level_editor->camera_scale - 0.1f);
144         }
145     } break;
146
147     case SDL_MOUSEBUTTONUP:
148     case SDL_MOUSEBUTTONDOWN: {
149         bool selected = false;
150         if (color_picker_mouse_button(
151                 &level_editor->color_picker,
152                 &event->button,
153                 &selected) < 0) {
154             return -1;
155         }
156
157         if (layer_picker_mouse_button(
158                 &level_editor->layer_picker,
159                 camera,
160                 &event->button,
161                 &selected) < 0) {
162             return -1;
163         }
164
165         switch (level_editor->layer_picker) {
166         case LAYER_PICKER_BOXES: {
167             level_editor->current_rect_layer = level_editor->boxes_rect_layer;
168         } break;
169         case LAYER_PICKER_PLATFORMS: {
170             level_editor->current_rect_layer = level_editor->platforms_rect_layer;
171         } break;
172         case LAYER_PICKER_BACK_PLATFORMS: {
173             level_editor->current_rect_layer = level_editor->back_platforms_rect_layer;
174         } break;
175         case LAYER_PICKER_GOALS: {
176             level_editor->current_point_rect_layer = level_editor->goals_rect_layer;
177         } break;
178
179         default: {}
180         }
181
182         if (layer_picker_type(&level_editor->layer_picker) == LAYER_TYPE_RECT) {
183             if (!selected && proto_rect_mouse_button(
184                     &level_editor->proto_rect,
185                     &event->button,
186                     camera) < 0) {
187                 return -1;
188             }
189         } else {
190             point_layer_mouse_button(level_editor->current_point_rect_layer, &event->button);
191         }
192
193         if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_MIDDLE) {
194             level_editor->drag = true;
195         }
196
197         if (event->type == SDL_MOUSEBUTTONUP && event->button.button == SDL_BUTTON_MIDDLE) {
198             level_editor->drag = false;
199         }
200     } break;
201
202     case SDL_MOUSEMOTION: {
203         if (level_editor->drag) {
204             const Vec next_position = camera_map_screen(camera, event->motion.x, event->motion.y);
205             const Vec prev_position = camera_map_screen(
206                 camera,
207                 event->motion.x + event->motion.xrel,
208                 event->motion.y + event->motion.yrel);
209
210             vec_add(&level_editor->camera_position,
211                     vec_sub(next_position, prev_position));
212         }
213
214         if (proto_rect_mouse_motion(&level_editor->proto_rect, &event->motion, camera) < 0) {
215             return -1;
216         }
217     } break;
218     }
219
220     return 0;
221 }
222
223 int level_editor_focus_camera(LevelEditor *level_editor,
224                               Camera *camera)
225 {
226     camera_center_at(camera, level_editor->camera_position);
227     camera_scale(camera, level_editor->camera_scale);
228     return 0;
229 }
230
231 const RectLayer *level_editor_boxes(const LevelEditor *level_editor)
232 {
233     return level_editor->boxes_rect_layer;
234 }
235
236 const RectLayer *level_editor_platforms(const LevelEditor *level_editor)
237 {
238     return level_editor->platforms_rect_layer;
239 }
240
241 const RectLayer *level_editor_back_platforms(const LevelEditor *level_editor)
242 {
243     return level_editor->back_platforms_rect_layer;
244 }