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