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 |