]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor.c
(#814) TODOs
[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 "system/stacktrace.h"
9 #include "system/nth_alloc.h"
10 #include "system/lt.h"
11
12 #include "level_editor.h"
13
14 struct LevelEditor
15 {
16     Lt *lt;
17     Vec camera_position;
18     float camera_scale;
19     ProtoRect proto_rect;
20     ColorPicker color_picker;
21     // TODO(#805): boxes_layer is not connected with the level->boxes
22     Layer *boxes_layer;
23     Layer *platforms_layer;
24     Layer *back_platforms_layer;
25     // TODO: LevelEditor does not allow to switch the current layer
26     Layer *current_layer;
27     bool drag;
28 };
29
30 LevelEditor *create_level_editor(Layer *boxes_layer,
31                                  Layer *platforms_layer,
32                                  Layer *back_platforms_layer)
33 {
34     trace_assert(boxes_layer);
35     trace_assert(platforms_layer);
36     trace_assert(back_platforms_layer);
37
38     Lt *lt = create_lt();
39     if (lt == NULL) {
40         return NULL;
41     }
42
43     LevelEditor *level_editor = PUSH_LT(lt, nth_calloc(1, sizeof(LevelEditor)), free);
44     if (level_editor == NULL) {
45         RETURN_LT(lt, NULL);
46     }
47     level_editor->lt = lt;
48
49     level_editor->camera_position = vec(0.0f, 0.0f);
50     level_editor->camera_scale = 1.0f;
51     level_editor->proto_rect.color = rgba(1.0f, 0.0f, 0.0f, 1.0f);
52     level_editor->color_picker.position = vec(0.0f, 0.0f);
53     level_editor->color_picker.proto_rect = &level_editor->proto_rect;
54     level_editor->boxes_layer = PUSH_LT(lt, boxes_layer, destroy_layer);
55     level_editor->platforms_layer = PUSH_LT(lt, platforms_layer, destroy_layer);
56     level_editor->back_platforms_layer = PUSH_LT(lt, back_platforms_layer, destroy_layer);
57     level_editor->drag = false;
58     level_editor->current_layer = level_editor->platforms_layer;
59
60     return level_editor;
61 }
62
63 void destroy_level_editor(LevelEditor *level_editor)
64 {
65     trace_assert(level_editor);
66     RETURN_LT0(level_editor->lt);
67 }
68
69 int level_editor_render(const LevelEditor *level_editor,
70                         Camera *camera)
71 {
72     trace_assert(level_editor);
73     trace_assert(camera);
74
75     if (layer_render(level_editor->back_platforms_layer, camera) < 0) {
76         return -1;
77     }
78
79     if (layer_render(level_editor->boxes_layer, camera) < 0) {
80         return -1;
81     }
82
83     if (layer_render(level_editor->platforms_layer, camera) < 0) {
84         return -1;
85     }
86
87     if (proto_rect_render(&level_editor->proto_rect, camera) < 0) {
88         return -1;
89     }
90
91     if (color_picker_render(&level_editor->color_picker, camera) < 0) {
92         return -1;
93     }
94
95     return 0;
96 }
97
98 int level_editor_update(LevelEditor *level_editor,
99                         float delta_time)
100 {
101     trace_assert(level_editor);
102
103     if (proto_rect_update(&level_editor->proto_rect, delta_time) < 0) {
104         return -1;
105     }
106
107     return 0;
108 }
109
110 int level_editor_event(LevelEditor *level_editor,
111                        const SDL_Event *event,
112                        const Camera *camera)
113 {
114     trace_assert(level_editor);
115     trace_assert(event);
116
117     (void) camera;
118
119     switch (event->type) {
120     case SDL_MOUSEWHEEL: {
121         // TODO(#679): zooming in edit mode is not smooth enough
122         if (event->wheel.y > 0) {
123             level_editor->camera_scale += 0.1f;
124         } else if (event->wheel.y < 0) {
125             level_editor->camera_scale = fmaxf(0.1f, level_editor->camera_scale - 0.1f);
126         }
127     } break;
128
129     case SDL_MOUSEBUTTONUP:
130     case SDL_MOUSEBUTTONDOWN: {
131         if (event->type == SDL_MOUSEBUTTONUP) {
132             const Vec position = camera_map_screen(camera, event->button.x, event->button.y);
133             if (layer_delete_rect_at(level_editor->current_layer, position) < 0) {
134                 return -1;
135             }
136         }
137
138         bool selected = false;
139         if (color_picker_mouse_button(
140                 &level_editor->color_picker,
141                 &event->button,
142                 &selected) < 0) {
143             return -1;
144         }
145
146         if (!selected && proto_rect_mouse_button(
147                 &level_editor->proto_rect,
148                 &event->button,
149                 level_editor->current_layer,
150                 camera) < 0) {
151             return -1;
152         }
153
154         if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_MIDDLE) {
155             level_editor->drag = true;
156         }
157
158         if (event->type == SDL_MOUSEBUTTONUP && event->button.button == SDL_BUTTON_MIDDLE) {
159             level_editor->drag = false;
160         }
161     } break;
162
163     case SDL_MOUSEMOTION: {
164         if (level_editor->drag) {
165             const Vec next_position = camera_map_screen(camera, event->motion.x, event->motion.y);
166             const Vec prev_position = camera_map_screen(
167                 camera,
168                 event->motion.x + event->motion.xrel,
169                 event->motion.y + event->motion.yrel);
170
171             vec_add(&level_editor->camera_position,
172                     vec_sub(next_position, prev_position));
173         }
174
175         if (proto_rect_mouse_motion(&level_editor->proto_rect, &event->motion, camera) < 0) {
176             return -1;
177         }
178     } break;
179     }
180
181     return 0;
182 }
183
184 int level_editor_focus_camera(LevelEditor *level_editor,
185                               Camera *camera)
186 {
187     camera_center_at(camera, level_editor->camera_position);
188     camera_scale(camera, level_editor->camera_scale);
189     return 0;
190 }
191
192 const Layer *level_editor_boxes(const LevelEditor *level_editor)
193 {
194     return level_editor->boxes_layer;
195 }
196
197 const Layer *level_editor_platforms(const LevelEditor *level_editor)
198 {
199     return level_editor->platforms_layer;
200 }