]> git.lizzy.rs Git - nothing.git/blob - src/math/rect.c
Merge pull request #228 from tsoding/222
[nothing.git] / src / math / rect.c
1 #include <SDL2/SDL.h>
2 #include <assert.h>
3 #include <math.h>
4 #include <string.h>
5
6 #include "rect.h"
7
8 rect_t rect(float x, float y, float w, float h)
9 {
10     const rect_t result = {
11         .x = x,
12         .y = y,
13         .w = w,
14         .h = h
15     };
16
17     return result;
18 }
19
20 rect_t rect_from_vecs(point_t position, vec_t size)
21 {
22     return rect(position.x, position.y, size.x, size.y);
23 }
24
25 rect_t rect_from_sdl(const SDL_Rect *rect)
26 {
27     const rect_t 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_t rects_overlap_area(rect_t rect1, rect_t 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_t 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_t rect1, rect_t 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_t 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_t object, rect_t obstacle, int *sides)
69 {
70     assert(sides);
71
72     rect_t 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_t object_side = rect_side(object, side);
77             line_t 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_t rect_side(rect_t rect, rect_side_t 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_t 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_t rect_from_point(point_t p, float w, float h)
133 {
134     rect_t 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_t rect, point_t 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_t 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 }