]> git.lizzy.rs Git - nothing.git/blob - src/game/level/background.c
create_lt() -> {0}
[nothing.git] / src / game / level / background.c
1 #include "system/stacktrace.h"
2
3 #include "game/level/background.h"
4 #include "math/rand.h"
5 #include "math/rect.h"
6 #include "system/line_stream.h"
7 #include "system/lt.h"
8 #include "system/nth_alloc.h"
9 #include "system/log.h"
10
11 #define BACKGROUND_CHUNK_COUNT 5
12 #define BACKGROUND_CHUNK_WIDTH 250.0f
13 #define BACKGROUND_CHUNK_HEIGHT 250.0f
14
15 static void chunk_of_point(Point p, int *x, int *y);
16 int render_chunk(const Background *background,
17                  Camera *camera,
18                  int x, int y,
19                  Color color,
20                  Vec position,
21                  float parallax);
22
23 struct Background
24 {
25     Lt lt;
26     Color base_color;
27     Vec position;
28     int debug_mode;
29 };
30
31 Background *create_background(Color base_color)
32 {
33     Lt lt = {0};
34     if (lt == NULL) {
35         return NULL;
36     }
37
38     Background *background = PUSH_LT(lt, nth_calloc(1, sizeof(Background)), free);
39     if (background == NULL) {
40         RETURN_LT(lt, NULL);
41     }
42
43     background->base_color = base_color;
44     background->position = vec(0.0f, 0.0f);
45     background->debug_mode = 0;
46     background->lt = lt;
47
48     return background;
49 }
50
51 Background *create_background_from_line_stream(LineStream *line_stream)
52 {
53     char color[7];
54     if (sscanf(line_stream_next(line_stream), "%6s", color) == EOF) {
55         log_fail("Could not read background's color\n");
56         return NULL;
57     }
58
59     return create_background(hexstr(color));
60 }
61
62 void destroy_background(Background *background)
63 {
64     trace_assert(background);
65     RETURN_LT0(background->lt);
66 }
67
68 /* TODO(#182): background chunks are randomly disappearing when the size of the window is less than size of the chunk  */
69 int background_render(const Background *background,
70                       Camera *camera)
71 {
72     trace_assert(background);
73     trace_assert(camera);
74
75     if (camera_clear_background(
76             camera,
77             background->base_color) < 0) {
78         return -1;
79     }
80
81     const Rect view_port = camera_view_port(camera);
82     const Vec position = vec(view_port.x, view_port.y);
83
84     for (int l = 0; l < 3; ++l) {
85         const float parallax = 1.0f - 0.2f * (float)l;
86
87         int min_x = 0, min_y = 0;
88         chunk_of_point(vec(view_port.x - position.x * parallax,
89                            view_port.y - position.y * parallax),
90                        &min_x, &min_y);
91
92         int max_x = 0, max_y = 0;
93         chunk_of_point(vec(view_port.x - position.x * parallax + view_port.w,
94                            view_port.y - position.y * parallax + view_port.h),
95                        &max_x, &max_y);
96
97         for (int x = min_x; x <= max_x; ++x) {
98             for (int y = min_y; y <= max_y; ++y) {
99                 if (render_chunk(
100                         background,
101                         camera,
102                         x, y,
103                         color_darker(background->base_color, 0.05f * (float)(l + 1)),
104                         position,
105                         parallax) < 0) {
106                     return -1;
107                 }
108             }
109         }
110     }
111
112     return 0;
113 }
114
115 /* Private Function */
116
117 static void chunk_of_point(Point p, int *x, int *y)
118 {
119     trace_assert(x);
120     trace_assert(y);
121     *x = (int) (p.x / BACKGROUND_CHUNK_WIDTH);
122     *y = (int) (p.y / BACKGROUND_CHUNK_HEIGHT);
123 }
124
125 int render_chunk(const Background *background,
126                  Camera *camera,
127                  int chunk_x, int chunk_y,
128                  Color color,
129                  Vec position,
130                  float parallax)
131 {
132     (void) background;
133
134     if (background->debug_mode) {
135         return 0;
136     }
137
138     srand((unsigned int)(roundf((float)chunk_x + (float)chunk_y + parallax)));
139
140     for (size_t i = 0; i < BACKGROUND_CHUNK_COUNT; ++i) {
141         const float rect_x = rand_float_range((float) chunk_x * BACKGROUND_CHUNK_WIDTH,
142                                               (float) (chunk_x + 1) * BACKGROUND_CHUNK_WIDTH);
143         const float rect_y = rand_float_range((float) chunk_y * BACKGROUND_CHUNK_HEIGHT,
144                                               (float) (chunk_y + 1) * BACKGROUND_CHUNK_HEIGHT);
145         const float rect_w = rand_float_range(0.0f, BACKGROUND_CHUNK_WIDTH * 0.5f);
146         const float rect_h = rand_float_range(rect_w * 0.5f, rect_w * 1.5f);
147
148         if (camera_fill_rect(
149                 camera,
150                 rect(rect_x + position.x * parallax,
151                      rect_y + position.y * parallax,
152                      rect_w,
153                      rect_h),
154                 color) < 0) {
155             return -1;
156         }
157     }
158
159     return 0;
160 }
161
162 void background_toggle_debug_mode(Background *background)
163 {
164     background->debug_mode = !background->debug_mode;
165 }