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