]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor.c
(#819) Integrate LevelEditor Regions with Level
[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/rect_layer.h"
8 #include "game/level/level_editor/point_layer.h"
9 #include "game/level/level_editor/player_layer.h"
10 #include "game/level/level_editor/layer_picker.h"
11 #include "system/stacktrace.h"
12 #include "system/nth_alloc.h"
13 #include "system/lt.h"
14 #include "system/log.h"
15
16 #include "level_editor.h"
17
18 struct LevelEditor
19 {
20     Lt *lt;
21     Vec camera_position;
22     float camera_scale;
23     LayerPicker layer_picker;
24
25     RectLayer *boxes_layer;
26     RectLayer *platforms_layer;
27     RectLayer *back_platforms_layer;
28     PointLayer *goals_layer;
29     PlayerLayer *player_layer;
30     RectLayer *lava_layer;
31     RectLayer *regions_layer;
32     LayerPtr layers[LAYER_PICKER_N];
33
34     bool drag;
35 };
36
37 LevelEditor *create_level_editor(RectLayer *boxes_layer,
38                                  RectLayer *platforms_layer,
39                                  RectLayer *back_platforms_layer,
40                                  PointLayer *goals_layer,
41                                  PlayerLayer *player_layer,
42                                  RectLayer *lava_layer,
43                                  RectLayer *regions_layer)
44 {
45     trace_assert(boxes_layer);
46     trace_assert(platforms_layer);
47     trace_assert(back_platforms_layer);
48     trace_assert(goals_layer);
49     trace_assert(player_layer);
50     trace_assert(lava_layer);
51     trace_assert(regions_layer);
52
53     Lt *lt = create_lt();
54
55     LevelEditor *level_editor = PUSH_LT(lt, nth_calloc(1, sizeof(LevelEditor)), free);
56     if (level_editor == NULL) {
57         RETURN_LT(lt, NULL);
58     }
59     level_editor->lt = lt;
60
61     level_editor->camera_position = vec(0.0f, 0.0f);
62     level_editor->camera_scale = 1.0f;
63
64     level_editor->boxes_layer = PUSH_LT(lt, boxes_layer, destroy_rect_layer);
65     level_editor->platforms_layer = PUSH_LT(lt, platforms_layer, destroy_rect_layer);
66     level_editor->back_platforms_layer = PUSH_LT(lt, back_platforms_layer, destroy_rect_layer);
67     level_editor->goals_layer = PUSH_LT(lt, goals_layer, destroy_point_layer);
68     level_editor->player_layer = PUSH_LT(lt, player_layer, destroy_player_layer);
69     level_editor->lava_layer = PUSH_LT(lt, lava_layer, destroy_rect_layer);
70     level_editor->regions_layer = PUSH_LT(lt, regions_layer, destroy_rect_layer);
71
72     level_editor->layers[LAYER_PICKER_BOXES] = rect_layer_as_layer(level_editor->boxes_layer);
73     level_editor->layers[LAYER_PICKER_PLATFORMS] = rect_layer_as_layer(level_editor->platforms_layer);
74     level_editor->layers[LAYER_PICKER_BACK_PLATFORMS] = rect_layer_as_layer(level_editor->back_platforms_layer);
75     level_editor->layers[LAYER_PICKER_GOALS] = point_layer_as_layer(level_editor->goals_layer);
76     level_editor->layers[LAYER_PICKER_PLAYER] = player_layer_as_layer(level_editor->player_layer);
77     level_editor->layers[LAYER_PICKER_LAVA] = rect_layer_as_layer(level_editor->lava_layer);
78     level_editor->layers[LAYER_PICKER_REGIONS] = rect_layer_as_layer(level_editor->regions_layer);
79
80     size_t n = rect_layer_count(level_editor->regions_layer);
81     const char *ids = rect_layer_ids(level_editor->regions_layer);
82     log_info("Regions:\n");
83     for (size_t i = 0; i < n; ++i) {
84         log_info("%s\n", ids + i * 36);
85     }
86
87     level_editor->layer_picker = LAYER_PICKER_BOXES;
88
89     level_editor->drag = false;
90
91     return level_editor;
92 }
93
94 void destroy_level_editor(LevelEditor *level_editor)
95 {
96     trace_assert(level_editor);
97     RETURN_LT0(level_editor->lt);
98 }
99
100 int level_editor_render(const LevelEditor *level_editor,
101                         Camera *camera)
102 {
103     trace_assert(level_editor);
104     trace_assert(camera);
105
106     for (size_t i = 0; i < LAYER_PICKER_N; ++i) {
107         if (layer_render(
108                 level_editor->layers[i],
109                 camera,
110                 i == level_editor->layer_picker ? 1.0f : 0.5f) < 0) {
111             return -1;
112         }
113     }
114
115     if (layer_picker_render(&level_editor->layer_picker, camera) < 0) {
116         return -1;
117     }
118
119     return 0;
120 }
121
122 int level_editor_event(LevelEditor *level_editor,
123                        const SDL_Event *event,
124                        const Camera *camera)
125 {
126     trace_assert(level_editor);
127     trace_assert(event);
128     trace_assert(camera);
129
130     switch (event->type) {
131     case SDL_MOUSEWHEEL: {
132         // TODO(#679): zooming in edit mode is not smooth enough
133         if (event->wheel.y > 0) {
134             level_editor->camera_scale += 0.1f;
135         } else if (event->wheel.y < 0) {
136             level_editor->camera_scale = fmaxf(0.1f, level_editor->camera_scale - 0.1f);
137         }
138     } break;
139
140     case SDL_MOUSEBUTTONUP:
141     case SDL_MOUSEBUTTONDOWN: {
142         if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_MIDDLE) {
143             level_editor->drag = true;
144         }
145
146         if (event->type == SDL_MOUSEBUTTONUP && event->button.button == SDL_BUTTON_MIDDLE) {
147             level_editor->drag = false;
148         }
149     } break;
150
151     case SDL_MOUSEMOTION: {
152         if (level_editor->drag) {
153             const Vec next_position = camera_map_screen(camera, event->motion.x, event->motion.y);
154             const Vec prev_position = camera_map_screen(
155                 camera,
156                 event->motion.x + event->motion.xrel,
157                 event->motion.y + event->motion.yrel);
158
159             vec_add(&level_editor->camera_position,
160                     vec_sub(next_position, prev_position));
161         }
162
163     } break;
164     }
165
166     bool selected = false;
167     if (layer_picker_event(
168             &level_editor->layer_picker,
169             event,
170             camera,
171             &selected) < 0) {
172         return -1;
173     }
174
175     if (!selected) {
176         if (layer_event(
177                 level_editor->layers[level_editor->layer_picker],
178                 event,
179                 camera) < 0) {
180             return -1;
181         }
182     }
183
184     return 0;
185 }
186
187 int level_editor_focus_camera(LevelEditor *level_editor,
188                               Camera *camera)
189 {
190     camera_center_at(camera, level_editor->camera_position);
191     camera_scale(camera, level_editor->camera_scale);
192     return 0;
193 }
194
195 const RectLayer *level_editor_boxes(const LevelEditor *level_editor)
196 {
197     return level_editor->boxes_layer;
198 }
199
200 const RectLayer *level_editor_platforms(const LevelEditor *level_editor)
201 {
202     return level_editor->platforms_layer;
203 }
204
205 const RectLayer *level_editor_back_platforms(const LevelEditor *level_editor)
206 {
207     return level_editor->back_platforms_layer;
208 }
209
210 const PointLayer *level_editor_goals_layer(const LevelEditor *level_editor)
211 {
212     return level_editor->goals_layer;
213 }
214
215 const PlayerLayer *level_editor_player_layer(const LevelEditor *level_editor)
216 {
217     return level_editor->player_layer;
218 }
219
220 const RectLayer *level_editor_lava_layer(const LevelEditor *level_editor)
221 {
222     return level_editor->lava_layer;
223 }
224
225 const RectLayer *level_editor_regions_layer(const LevelEditor *level_editor)
226 {
227     return level_editor->regions_layer;
228 }