]> git.lizzy.rs Git - nothing.git/blob - src/game/level_picker.c
Merge pull request #1197 from tsoding/cleanup
[nothing.git] / src / game / level_picker.c
1 #include <stdio.h>
2
3 #include "./level_picker.h"
4 #include "game/level/background.h"
5 #include "game/sprite_font.h"
6 #include "system/lt.h"
7 #include "system/nth_alloc.h"
8 #include "system/stacktrace.h"
9 #include "system/str.h"
10 #include "ui/list_selector.h"
11 #include "system/log.h"
12 #include "game/level_folder.h"
13 #include "ui/wiggly_text.h"
14 #include "ui/slider.h"
15
16 #define TITLE_MARGIN_TOP 100.0f
17 #define TITLE_MARGIN_BOTTOM 100.0f
18
19 struct LevelPicker
20 {
21     Lt *lt;
22     Background background;
23     Vec2f camera_position;
24     LevelFolder level_folder;
25     WigglyText wiggly_text;
26     ListSelector list_selector;
27 };
28
29 static inline
30 const char *list_item_text(void *element)
31 {
32     trace_assert(element);
33     return ((LevelMetadata *)element)->title;
34 }
35
36 LevelPicker *create_level_picker(const char *dirpath)
37 {
38     trace_assert(dirpath);
39
40     Lt *lt = create_lt();
41
42     LevelPicker *level_picker = PUSH_LT(
43         lt,
44         nth_calloc(1, sizeof(LevelPicker)),
45         free);
46     if (level_picker == NULL) {
47         RETURN_LT(lt, NULL);
48     }
49     level_picker->lt = lt;
50
51     level_picker->background = create_background(hexstr("073642"));
52
53     level_picker->camera_position = vec(0.0f, 0.0f);
54
55     level_picker->level_folder = create_level_folder();
56     level_folder_read("./assets/levels", &level_picker->level_folder);
57
58     level_picker->wiggly_text = (WigglyText) {
59         .text = "Select Level",
60         .scale = {10.0f, 10.0f},
61         .color = COLOR_WHITE,
62     };
63
64     level_picker->list_selector.items = level_picker->level_folder.metadatas;
65     level_picker->list_selector.font_scale = vec(5.0f, 5.0f);
66     level_picker->list_selector.padding_bottom = 50.0f;
67     level_picker->list_selector.list_item_text = list_item_text;
68
69     return level_picker;
70 }
71
72 void destroy_level_picker(LevelPicker *level_picker)
73 {
74     trace_assert(level_picker);
75     destroy_level_folder(level_picker->level_folder);
76     RETURN_LT0(level_picker->lt);
77 }
78
79 int level_picker_render(const LevelPicker *level_picker,
80                         const Camera *camera)
81 {
82     trace_assert(level_picker);
83
84     const Rect viewport = camera_view_port_screen(camera);
85
86     if (background_render(&level_picker->background, camera) < 0) {
87         return -1;
88     }
89
90     const Vec2f title_size = wiggly_text_size(&level_picker->wiggly_text);
91
92     wiggly_text_render(
93         &level_picker->wiggly_text,
94         camera,
95         vec(viewport.w * 0.5f - title_size.x * 0.5f, TITLE_MARGIN_TOP));
96
97     list_selector_render(camera, &level_picker->list_selector);
98
99     {
100         /* CSS */
101         const float padding = 20.0f;
102         const Vec2f size = vec(3.0f, 3.0f);
103         const Vec2f position = vec(0.0f, viewport.h - size.y * FONT_CHAR_HEIGHT);
104
105         /* HTML */
106         camera_render_text_screen(
107             camera,
108             "Press 'N' to create new level",
109             size,
110             COLOR_WHITE,
111             vec(position.x + padding,
112                 position.y - padding));
113     }
114
115     return 0;
116 }
117
118 int level_picker_update(LevelPicker *level_picker,
119                         float delta_time)
120 {
121     trace_assert(level_picker);
122
123     vec_add(&level_picker->camera_position,
124             vec(50.0f * delta_time, 0.0f));
125
126     if (wiggly_text_update(&level_picker->wiggly_text, delta_time) < 0) {
127         return -1;
128     }
129
130     return 0;
131 }
132
133 int level_picker_event(LevelPicker *level_picker,
134                        const SDL_Event *event)
135 {
136     trace_assert(level_picker);
137     trace_assert(event);
138
139     switch (event->type) {
140     case SDL_WINDOWEVENT: {
141         switch (event->window.event) {
142         case SDL_WINDOWEVENT_SHOWN:
143         case SDL_WINDOWEVENT_SIZE_CHANGED: {
144             const Vec2f font_scale = vec(5.0f, 5.0f);
145             const float padding_bottom = 50.0f;
146
147             int width;
148             SDL_GetRendererOutputSize(SDL_GetRenderer(SDL_GetWindowFromID(event->window.windowID)), &width, NULL);
149
150             const Vec2f title_size = wiggly_text_size(&level_picker->wiggly_text);
151
152             const Vec2f selector_size = list_selector_size(
153                 &level_picker->list_selector,
154                 font_scale,
155                 padding_bottom);
156
157             level_picker->list_selector.position =
158                 vec((float)width * 0.5f - selector_size.x * 0.5f,
159                     TITLE_MARGIN_TOP + title_size.y + TITLE_MARGIN_BOTTOM);
160         } break;
161         }
162     } break;
163     }
164
165     return list_selector_event(&level_picker->list_selector, event);
166 }
167
168 int level_picker_input(LevelPicker *level_picker,
169                        const Uint8 *const keyboard_state,
170                        SDL_Joystick *the_stick_of_joy)
171 {
172     trace_assert(level_picker);
173     trace_assert(keyboard_state);
174     (void) the_stick_of_joy;
175     return 0;
176 }
177
178 const char *level_picker_selected_level(const LevelPicker *level_picker)
179 {
180     trace_assert(level_picker);
181
182     if (level_picker->list_selector.selected_item < 0) {
183         return NULL;
184     }
185
186     LevelMetadata *metadata = dynarray_pointer_at(
187         &level_picker->level_folder.metadatas,
188         (size_t)level_picker->list_selector.selected_item);
189
190     return metadata->filepath;
191 }
192
193 void level_picker_clean_selection(LevelPicker *level_picker)
194 {
195     trace_assert(level_picker);
196     level_picker->list_selector.selected_item = -1;
197 }
198
199 int level_picker_enter_camera_event(LevelPicker *level_picker,
200                                     Camera *camera)
201 {
202     camera_center_at(camera, level_picker->camera_position);
203     return 0;
204 }