]> git.lizzy.rs Git - nothing.git/blob - src/rect.c
Merge pull request #124 from tsoding/117
[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 rects_overlap_area(rect_t rect1, rect_t rect2)
27 {
28     float x1 = fmaxf(rect1.x, rect2.x);
29     float y1 = fmaxf(rect1.y, rect2.y);
30     float x2 = fminf(rect1.x + rect1.w, rect2.x + rect2.w);
31     float y2 = fminf(rect1.y + rect1.h, rect2.y + rect2.h);
32
33     rect_t result = {
34         .x = x1,
35         .y = y1,
36         .w = fmaxf(0.0f, x2 - x1),
37         .h = fmaxf(0.0f, y2 - y1)
38     };
39     return result;
40 }
41
42 int rects_overlap(rect_t rect1, rect_t rect2)
43 {
44     return rect1.x + rect1.w >= rect2.x
45         && rect2.x + rect2.w >= rect1.x
46         && rect2.y + rect2.h >= rect1.y
47         && rect1.y + rect1.h >= rect2.y;
48 }
49
50 float line_length(line_t line)
51 {
52     float dx = line.p1.x - line.p2.x;
53     float dy = line.p1.y - line.p2.y;
54     return sqrtf(dx * dx + dy * dy);
55 }
56
57 void rect_object_impact(const rect_t *object,
58                         const rect_t *obstacle,
59                         int *sides)
60 {
61     assert(object);
62     assert(obstacle);
63     assert(sides);
64
65     rect_t int_area = rects_overlap_area(*object, *obstacle);
66
67     if (int_area.w * int_area.h > 0.0f) {
68         for (int side = 0; side < RECT_SIDE_N; ++side) {
69             line_t object_side = rect_side(*object, side);
70             line_t int_side = rect_side(int_area, side);
71
72             if (line_length(int_side) > 10.0f) {
73                 sides[side] = sides[side] ||
74                     (fabs(object_side.p1.x - object_side.p2.x) < 1e-6
75                      && fabs(object_side.p1.x - int_side.p1.x) < 1e-6
76                      && fabs(object_side.p1.x - int_side.p2.x) < 1e-6)
77                     || (fabs(object_side.p1.y - object_side.p2.y) < 1e-6
78                         && fabs(object_side.p1.y - int_side.p1.y) < 1e-6
79                         && fabs(object_side.p1.y - int_side.p2.y) < 1e-6);
80             }
81         }
82     }
83 }
84
85 line_t rect_side(rect_t rect, rect_side_t side)
86 {
87     const float x1 = rect.x;
88     const float y1 = rect.y;
89     const float x2 = rect.x + rect.w;
90     const float y2 = rect.y + rect.h;
91
92     line_t result;
93
94     switch (side) {
95     case RECT_SIDE_LEFT:
96         result.p1.x = x1;
97         result.p1.y = y1;
98         result.p2.x = x1;
99         result.p2.y = y2;
100         break;
101     case RECT_SIDE_RIGHT:
102         result.p1.x = x2;
103         result.p1.y = y1;
104         result.p2.x = x2;
105         result.p2.y = y2;
106         break;
107     case RECT_SIDE_TOP:
108         result.p1.x = x1;
109         result.p1.y = y1;
110         result.p2.x = x2;
111         result.p2.y = y1;
112         break;
113     case RECT_SIDE_BOTTOM:
114         result.p1.x = x1;
115         result.p1.y = y2;
116         result.p2.x = x2;
117         result.p2.y = y2;
118         break;
119     default: {}
120     }
121
122     return result;
123 }
124
125 rect_t rect_from_point(point_t p, float w, float h)
126 {
127     rect_t result = {
128         .x = p.x,
129         .y = p.y,
130         .w = w,
131         .h = h
132     };
133
134     return result;
135 }
136
137 int rect_contains_point(rect_t rect, point_t p)
138 {
139     return rect.x <= p.x && p.x <= rect.x + rect.w
140         && rect.y <= p.y && p.y <= rect.y + rect.h;
141 }
142
143 SDL_Rect rect_for_sdl(rect_t rect)
144 {
145     const SDL_Rect result = {
146         .x = (int) roundf(rect.x),
147         .y = (int) roundf(rect.y),
148         .w = (int) roundf(rect.w),
149         .h = (int) roundf(rect.h)
150     };
151
152     return result;
153 }