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