]> git.lizzy.rs Git - nothing.git/blob - src/rect.c
Move mat3x3 to math "subpackage"
[nothing.git] / src / rect.c
1 #include <string.h>
2 #include <assert.h>
3 #include <math.h>
4
5 #include <SDL2/SDL.h>
6
7 #include "./rect.h"
8
9 rect_t rect(float x, float y, float w, float h)
10 {
11     const rect_t result = {
12         .x = x,
13         .y = y,
14         .w = w,
15         .h = h
16     };
17
18     return result;
19 }
20
21 rect_t rect_from_vecs(point_t position, vec_t size)
22 {
23     return rect(position.x, position.y, size.x, size.y);
24 }
25
26 rect_t rect_from_sdl(const SDL_Rect *rect)
27 {
28     const rect_t result = {
29         .x = (float) rect->x,
30         .y = (float) rect->y,
31         .w = (float) rect->w,
32         .h = (float) rect->h
33     };
34
35     return result;
36 }
37
38 rect_t rects_overlap_area(rect_t rect1, rect_t rect2)
39 {
40     float x1 = fmaxf(rect1.x, rect2.x);
41     float y1 = fmaxf(rect1.y, rect2.y);
42     float x2 = fminf(rect1.x + rect1.w, rect2.x + rect2.w);
43     float y2 = fminf(rect1.y + rect1.h, rect2.y + rect2.h);
44
45     rect_t result = {
46         .x = x1,
47         .y = y1,
48         .w = fmaxf(0.0f, x2 - x1),
49         .h = fmaxf(0.0f, y2 - y1)
50     };
51     return result;
52 }
53
54 int rects_overlap(rect_t rect1, rect_t rect2)
55 {
56     return rect1.x + rect1.w >= rect2.x
57         && rect2.x + rect2.w >= rect1.x
58         && rect2.y + rect2.h >= rect1.y
59         && rect1.y + rect1.h >= rect2.y;
60 }
61
62 float line_length(line_t line)
63 {
64     float dx = line.p1.x - line.p2.x;
65     float dy = line.p1.y - line.p2.y;
66     return sqrtf(dx * dx + dy * dy);
67 }
68
69 void rect_object_impact(const rect_t *object,
70                         const rect_t *obstacle,
71                         int *sides)
72 {
73     assert(object);
74     assert(obstacle);
75     assert(sides);
76
77     rect_t int_area = rects_overlap_area(*object, *obstacle);
78
79     if (int_area.w * int_area.h > 0.0f) {
80         for (int side = 0; side < RECT_SIDE_N; ++side) {
81             line_t object_side = rect_side(*object, side);
82             line_t int_side = rect_side(int_area, side);
83
84             if (line_length(int_side) > 10.0f) {
85                 sides[side] = sides[side] ||
86                     (fabs(object_side.p1.x - object_side.p2.x) < 1e-6
87                      && fabs(object_side.p1.x - int_side.p1.x) < 1e-6
88                      && fabs(object_side.p1.x - int_side.p2.x) < 1e-6)
89                     || (fabs(object_side.p1.y - object_side.p2.y) < 1e-6
90                         && fabs(object_side.p1.y - int_side.p1.y) < 1e-6
91                         && fabs(object_side.p1.y - int_side.p2.y) < 1e-6);
92             }
93         }
94     }
95 }
96
97 line_t rect_side(rect_t rect, rect_side_t side)
98 {
99     const float x1 = rect.x;
100     const float y1 = rect.y;
101     const float x2 = rect.x + rect.w;
102     const float y2 = rect.y + rect.h;
103
104     line_t result;
105
106     switch (side) {
107     case RECT_SIDE_LEFT:
108         result.p1.x = x1;
109         result.p1.y = y1;
110         result.p2.x = x1;
111         result.p2.y = y2;
112         break;
113     case RECT_SIDE_RIGHT:
114         result.p1.x = x2;
115         result.p1.y = y1;
116         result.p2.x = x2;
117         result.p2.y = y2;
118         break;
119     case RECT_SIDE_TOP:
120         result.p1.x = x1;
121         result.p1.y = y1;
122         result.p2.x = x2;
123         result.p2.y = y1;
124         break;
125     case RECT_SIDE_BOTTOM:
126         result.p1.x = x1;
127         result.p1.y = y2;
128         result.p2.x = x2;
129         result.p2.y = y2;
130         break;
131     default: {}
132     }
133
134     return result;
135 }
136
137 rect_t rect_from_point(point_t p, float w, float h)
138 {
139     rect_t result = {
140         .x = p.x,
141         .y = p.y,
142         .w = w,
143         .h = h
144     };
145
146     return result;
147 }
148
149 int rect_contains_point(rect_t rect, point_t p)
150 {
151     return rect.x <= p.x && p.x <= rect.x + rect.w
152         && rect.y <= p.y && p.y <= rect.y + rect.h;
153 }
154
155 SDL_Rect rect_for_sdl(rect_t rect)
156 {
157     const SDL_Rect result = {
158         .x = (int) roundf(rect.x),
159         .y = (int) roundf(rect.y),
160         .w = (int) roundf(rect.w),
161         .h = (int) roundf(rect.h)
162     };
163
164     return result;
165 }