GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 117 / 0 / 117
Functions: 100.0% 7 / 0 / 7
Branches: 100.0% 70 / 0 / 70

physic/src/physic.c
Line Branch Exec Source
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (c) 2026 Manuel Hernández Méndez
5 *
6 * Authors:
7 * Manuel Hernández Méndez <maherme.dev@gmail.com>
8 */
9
10 #include "physic.h"
11 #include "graph.h"
12 #include "utils.h"
13 #include <stdbool.h>
14
15 void
16 11 physicMoveSprite(sprite_t *sprite, direction_t direction)
17 {
18
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 10 times.
11 if (!sprite)
19 {
20 1 return;
21 }
22
23
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 9 times.
10 if (!utilsCheckTimeout(sprite->last_update, sprite->time_to_move))
24 {
25 1 return;
26 }
27
28 9 sprite_coordinates_t coord;
29 9 graphGetSpriteCoordinates(sprite, &coord);
30
31
5/5
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 13 taken 2 times.
✓ Branch 9 → 16 taken 2 times.
✓ Branch 9 → 19 taken 2 times.
✓ Branch 9 → 22 taken 1 time.
9 switch (direction)
32 {
33 2 case RIGHT:
34
2/2
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 12 taken 1 time.
2 if (coord.x2 + sprite->pixels_to_move >= sprite->max_movement.right)
35 {
36 1 sprite->x = sprite->max_movement.right - sprite->width;
37 1 return;
38 }
39 1 sprite->x += sprite->pixels_to_move;
40 1 break;
41 2 case LEFT:
42
2/2
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 15 taken 1 time.
2 if (coord.x1 - sprite->pixels_to_move <= sprite->max_movement.left)
43 {
44 1 sprite->x = sprite->max_movement.left;
45 1 return;
46 }
47 1 sprite->x -= sprite->pixels_to_move;
48 1 break;
49 2 case UP:
50
2/2
✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 18 taken 1 time.
2 if (coord.y2 + sprite->pixels_to_move >= sprite->max_movement.up)
51 {
52 1 sprite->y = sprite->max_movement.up - sprite->height;
53 1 return;
54 }
55 1 sprite->y += sprite->pixels_to_move;
56 1 break;
57 2 case DOWN:
58
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 21 taken 1 time.
2 if (coord.y1 - sprite->pixels_to_move <= sprite->max_movement.down)
59 {
60 1 sprite->y = sprite->max_movement.down;
61 1 return;
62 }
63 1 sprite->y -= sprite->pixels_to_move;
64 1 break;
65 1 case INVALID_DIR:
66 default:
67 1 return;
68 break;
69 }
70
71 4 graphNextImageToPrint(sprite);
72 4 graphUpdateTimeSprite(sprite);
73 }
74
75 bool
76 6 physicCheckBorderCollision(const sprite_t *const sprite, direction_t direction)
77 {
78
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 5 times.
6 if (!sprite)
79 1 return false;
80
81 5 sprite_coordinates_t coord;
82 5 graphGetSpriteCoordinates(sprite, &coord);
83
84
5/5
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 1 time.
✓ Branch 6 → 9 taken 1 time.
✓ Branch 6 → 10 taken 1 time.
✓ Branch 6 → 11 taken 1 time.
5 switch (direction)
85 {
86 1 case UP:
87 1 return coord.y2 >= sprite->max_movement.up;
88 break;
89 1 case DOWN:
90 1 return coord.y1 <= sprite->max_movement.down;
91 break;
92 1 case RIGHT:
93 1 return coord.x2 >= sprite->max_movement.right;
94 break;
95 1 case LEFT:
96 1 return coord.x1 <= sprite->max_movement.left;
97 break;
98 1 case INVALID_DIR:
99 default:
100 1 break;
101 }
102
103 1 return false;
104 }
105
106 static bool
107 11 checkBoxesCollison(const sprite_coordinates_t *const coord1, const sprite_coordinates_t *const coord2)
108 {
109
4/4
✓ Branch 2 → 3 taken 8 times.
✓ Branch 2 → 4 taken 3 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 7 times.
11 bool separated_x = coord1->x2 < coord2->x1 || coord1->x1 > coord2->x2;
110
4/4
✓ Branch 6 → 7 taken 9 times.
✓ Branch 6 → 8 taken 2 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 8 times.
11 bool separated_y = coord1->y2 < coord2->y1 || coord1->y1 > coord2->y2;
111
112
4/4
✓ Branch 10 → 11 taken 7 times.
✓ Branch 10 → 13 taken 4 times.
✓ Branch 11 → 12 taken 5 times.
✓ Branch 11 → 13 taken 2 times.
11 return !(separated_x || separated_y);
113 }
114
115 bool
116 9 physicCheckSpritesBoxCollision(const sprite_t *const sprite1, const sprite_t *const sprite2)
117 {
118
4/4
✓ Branch 2 → 3 taken 7 times.
✓ Branch 2 → 4 taken 2 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 6 times.
9 if (!sprite1 || !sprite2)
119 {
120 3 return false;
121 }
122
123 6 sprite_coordinates_t coord1, coord2;
124 6 graphGetSpriteCoordinates(sprite1, &coord1);
125 6 graphGetSpriteCoordinates(sprite2, &coord2);
126
127 6 return checkBoxesCollison(&coord1, &coord2);
128 }
129
130 static bool
131 4 checkPixelsCollision(const sprite_t *const sprite1,
132 const sprite_coordinates_t *const coord1,
133 const sprite_t *const sprite2,
134 const sprite_coordinates_t *const coord2)
135 {
136 4 int overlap_left = coord1->x1 > coord2->x1 ? coord1->x1 : coord2->x1;
137 4 int overlap_right = coord1->x2 < coord2->x2 ? coord1->x2 : coord2->x2;
138 4 int overlap_bottom = coord1->y1 > coord2->y1 ? coord1->y1 : coord2->y1;
139 4 int overlap_top = coord1->y2 < coord2->y2 ? coord1->y2 : coord2->y2;
140
141
4/4
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 2 times.
4 if (overlap_left >= overlap_right || overlap_bottom >= overlap_top)
142 2 return false;
143
144 2 const uint8_t *img1 = (const uint8_t *)sprite1->image;
145 2 const uint8_t *img2 = (const uint8_t *)sprite2->image;
146
147
2/2
✓ Branch 13 → 6 taken 4 times.
✓ Branch 13 → 14 taken 1 time.
5 for (int y = overlap_bottom; y < overlap_top; y++)
148 {
149
2/2
✓ Branch 11 → 7 taken 7 times.
✓ Branch 11 → 12 taken 3 times.
10 for (int x = overlap_left; x < overlap_right; x++)
150 {
151 // Local coords in sprite1
152 7 int x1 = x - coord1->x1;
153 7 int y1 = (sprite1->height - 1) - (y - coord1->y1);
154
155 // Local coords in sprite2
156 7 int x2 = x - coord2->x1;
157 7 int y2 = (sprite2->height - 1) - (y - coord2->y1);
158
159 // RGBA buffer index
160 7 int idx1 = (y1 * sprite1->width + x1) * NUM_RGBA_CHANNELS;
161 7 int idx2 = (y2 * sprite2->width + x2) * NUM_RGBA_CHANNELS;
162
163 7 uint8_t alpha1 = img1[idx1 + 3];
164 7 uint8_t alpha2 = img2[idx2 + 3];
165
166
4/4
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 10 taken 5 times.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 1 time.
7 if (alpha1 && alpha2)
167 1 return true;
168 }
169 }
170
171 1 return false;
172 }
173
174 bool
175 8 physicCheckSpritesPixelCollision(const sprite_t *const sprite1, const sprite_t *const sprite2)
176 {
177
4/4
✓ Branch 2 → 3 taken 6 times.
✓ Branch 2 → 4 taken 2 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 5 times.
8 if (!sprite1 || !sprite2)
178 {
179 3 return false;
180 }
181
182 5 sprite_coordinates_t coord1, coord2;
183 5 graphGetSpriteCoordinates(sprite1, &coord1);
184 5 graphGetSpriteCoordinates(sprite2, &coord2);
185
186
2/2
✓ Branch 10 → 11 taken 4 times.
✓ Branch 10 → 13 taken 1 time.
5 if (checkBoxesCollison(&coord1, &coord2))
187 {
188 4 return checkPixelsCollision(sprite1, &coord1, sprite2, &coord2);
189 }
190
191 1 return false;
192 }
193
194 void
195 4 physicMakeFootprintSprite(const sprite_t *const sprite1, const sprite_t *const sprite2)
196 {
197 4 sprite_coordinates_t coord1, coord2;
198 4 graphGetSpriteCoordinates(sprite1, &coord1);
199 4 graphGetSpriteCoordinates(sprite2, &coord2);
200
201 4 int overlap_left = (coord1.x1 > coord2.x1) ? coord1.x1 : coord2.x1;
202 4 int overlap_right = (coord1.x2 < coord2.x2) ? coord1.x2 : coord2.x2;
203 4 int overlap_top = (coord1.y2 < coord2.y2) ? coord1.y2 : coord2.y2;
204 4 int overlap_bottom = (coord1.y1 > coord2.y1) ? coord1.y1 : coord2.y1;
205
206
4/4
✓ Branch 6 → 7 taken 3 times.
✓ Branch 6 → 8 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 2 times.
4 if (overlap_left >= overlap_right || overlap_bottom >= overlap_top)
207 2 return;
208
209 2 uint32_t *img1 = (uint32_t *)sprite1->image;
210 2 const uint32_t *img2 = (const uint32_t *)sprite2->image;
211
212
2/2
✓ Branch 17 → 10 taken 4 times.
✓ Branch 17 → 18 taken 2 times.
6 for (int y = overlap_bottom; y < overlap_top; y++)
213 {
214
2/2
✓ Branch 15 → 11 taken 8 times.
✓ Branch 15 → 16 taken 4 times.
12 for (int x = overlap_left; x < overlap_right; x++)
215 {
216 8 int x1 = x - coord1.x1;
217 8 int y1 = (sprite1->height - 1) - (y - coord1.y1);
218
219 8 int x2 = x - coord2.x1;
220 8 int y2 = (sprite2->height - 1) - (y - coord2.y1);
221
222 8 uint32_t *pixel1 = &img1[y1 * sprite1->width + x1];
223 8 uint32_t pixel2 = img2[y2 * sprite2->width + x2];
224
225 /* (alpha != 0) */
226
4/4
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 14 taken 6 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 1 time.
8 if ((*pixel1 & 0xFF000000) && (pixel2 & 0xFF000000))
227 {
228 1 *pixel1 = 0;
229 }
230 }
231 }
232 }
233