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