]> git.lizzy.rs Git - nothing.git/blob - src/game/level/platforms.c
16be32d95232b8718564b3cbe6812b7111cd5bb5
[nothing.git] / src / game / level / platforms.c
1 #include <SDL2/SDL.h>
2 #include <assert.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "platforms.h"
8 #include "system/error.h"
9 #include "system/lt.h"
10
11 struct platforms_t {
12     lt_t *lt;
13
14     rect_t *rects;
15     color_t *colors;
16     size_t rects_size;
17 };
18
19 // A wrapper for fclose to pass like lt_destroy_t
20 static void fclose_lt(void* file)
21 {
22     fclose(file);
23 }
24
25 platforms_t *create_platforms_from_stream(FILE *stream)
26 {
27     assert(stream);
28
29     lt_t *const lt = create_lt();
30     if (lt == NULL) {
31         return NULL;
32     }
33
34     platforms_t *platforms = PUSH_LT(lt, malloc(sizeof(platforms_t)), free);
35     if (platforms == NULL) {
36         throw_error(ERROR_TYPE_LIBC);
37         RETURN_LT(lt, NULL);
38     }
39
40     platforms->rects_size = 0;
41     if (fscanf(stream, "%lu", &platforms->rects_size) == EOF) {
42         throw_error(ERROR_TYPE_LIBC);
43         RETURN_LT(lt, NULL);
44     }
45
46     platforms->rects = PUSH_LT(lt, malloc(sizeof(rect_t) * platforms->rects_size), free);
47     if (platforms->rects == NULL) {
48         throw_error(ERROR_TYPE_LIBC);
49         RETURN_LT(lt, NULL);
50     }
51
52     platforms->colors = PUSH_LT(lt, malloc(sizeof(color_t) * platforms->rects_size), free);
53     if (platforms->colors == NULL) {
54         throw_error(ERROR_TYPE_LIBC);
55         RETURN_LT(lt, NULL);
56     }
57
58     char color[7];
59     for (size_t i = 0; i < platforms->rects_size; ++i) {
60         if (fscanf(stream, "%f%f%f%f%6s\n",
61                    &platforms->rects[i].x, &platforms->rects[i].y,
62                    &platforms->rects[i].w, &platforms->rects[i].h,
63                    color) < 0) {
64             throw_error(ERROR_TYPE_LIBC);
65             RETURN_LT(lt, NULL);
66         }
67         platforms->colors[i] = color_from_hexstr(color);
68     }
69
70     platforms->lt = lt;
71
72     return platforms;
73 }
74
75 platforms_t *create_platforms_from_file(const char *filename)
76 {
77     assert(filename);
78
79     FILE *platforms_file = fopen(filename, "r");
80     if (platforms_file == NULL) {
81         throw_error(ERROR_TYPE_LIBC);
82         return NULL;
83     }
84
85     platforms_t *platforms = create_platforms_from_stream(platforms_file);
86     if (platforms != NULL) {
87         fclose(platforms_file);
88         return NULL;
89     }
90
91     fclose(platforms_file);
92     return platforms;
93 }
94
95 void destroy_platforms(platforms_t *platforms)
96 {
97     assert(platforms);
98     RETURN_LT0(platforms->lt);
99 }
100
101 int platforms_save_to_file(const platforms_t *platforms,
102                            const char *filename)
103 {
104     assert(platforms);
105     assert(filename);
106
107     lt_t *const lt = create_lt();
108     if (lt == NULL) {
109         return -1;
110     }
111
112     FILE *platforms_file = PUSH_LT(lt, fopen(filename, "w"), fclose_lt);
113
114     if (platforms_file == NULL) {
115         throw_error(ERROR_TYPE_LIBC);
116         RETURN_LT(lt, -1);
117     }
118
119     for (size_t i = 0; i < platforms->rects_size; ++i) {
120         if (fprintf(platforms_file, "%f %f %f %f\n",
121                     platforms->rects[i].x, platforms->rects[i].y,
122                     platforms->rects[i].w, platforms->rects[i].h) < 0) {
123             throw_error(ERROR_TYPE_LIBC);
124             RETURN_LT(lt, -1);
125         }
126     }
127
128     RETURN_LT(lt, 0);
129 }
130
131 solid_ref_t platforms_as_solid(platforms_t *platforms)
132 {
133     solid_ref_t ref = {
134         .tag = SOLID_PLATFORMS,
135         .ptr = (void*)platforms
136     };
137
138     return ref;
139 }
140
141 int platforms_render(const platforms_t *platforms,
142                      const camera_t *camera)
143 {
144     for (size_t i = 0; i < platforms->rects_size; ++i) {
145         if (camera_fill_rect(
146                 camera,
147                 platforms->rects[i],
148                 platforms->colors[i]) < 0) {
149             throw_error(ERROR_TYPE_SDL2);
150             return -1;
151         }
152     }
153
154     return 0;
155 }
156
157 void platforms_touches_rect_sides(const platforms_t *platforms,
158                                   rect_t object,
159                                   int sides[RECT_SIDE_N])
160 {
161     assert(platforms);
162
163     for (size_t i = 0; i < platforms->rects_size; ++i) {
164         rect_object_impact(object, platforms->rects[i], sides);
165     }
166 }
167
168 void platforms_apply_force(platforms_t *platforms,
169                            vec_t force)
170 {
171     (void) platforms;
172     (void) force;
173     /* Platforms have infinite mass and a fixed position in the
174      * space */
175 }