Line data Source code
1 : /*
2 : * primrect.c
3 : * Patater GUI Kit
4 : *
5 : * Created by Jaeden Amero on 2021-01-15.
6 : * Copyright 2021. SPDX-License-Identifier: AGPL-3.0-or-later
7 : */
8 :
9 : #include "guikit/primrect.h"
10 :
11 12 : static int min(int a, int b)
12 : {
13 12 : return a < b ? a : b;
14 : }
15 :
16 12 : static int max(int a, int b)
17 : {
18 12 : return a > b ? a : b;
19 : }
20 :
21 0 : void InitRect(struct Rect *rect, int x, int y, int w, int h)
22 : {
23 0 : rect->left = x;
24 0 : rect->top = y;
25 0 : rect->right = x + w - 1;
26 0 : rect->bottom = y + h - 1;
27 0 : }
28 :
29 4 : void RectFromLine(struct Rect *rect, int x0, int y0, int x1, int y1)
30 : {
31 : /* Create the smallest rectangle that will contain the line segment. */
32 4 : rect->left = min(x0, x1);
33 4 : rect->top = min(y0, y1);
34 4 : rect->right = max(x0, x1);
35 4 : rect->bottom = max(y0, y1);
36 4 : }
37 :
38 4 : void NormalizedRect(struct Rect *rect, const struct Rect *r)
39 : {
40 4 : RectFromLine(rect, r->left, r->top, r->right, r->bottom);
41 4 : }
42 :
43 6 : static int RectIsEmpty(const struct Rect *rect)
44 : {
45 : /* XXX Change this when making bottom inclusive */
46 6 : if (rect->bottom <= rect->top)
47 : {
48 3 : return 1;
49 : }
50 :
51 3 : if (rect->right <= rect->left)
52 : {
53 0 : return 1;
54 : }
55 :
56 3 : return 0;
57 : }
58 :
59 4 : int RectUnion(const struct Rect *a, const struct Rect *b, struct Rect *u)
60 : {
61 4 : if (RectIsEmpty(a))
62 : {
63 2 : *u = *b;
64 2 : return 0;
65 : }
66 :
67 2 : if (RectIsEmpty(b))
68 : {
69 1 : *u = *a;
70 1 : return 0;
71 : }
72 :
73 1 : u->left = min(a->left, b->left);
74 1 : u->top = min(a->top, b->top);
75 1 : u->right = max(a->right, b->right);
76 1 : u->bottom = max(a->bottom, b->bottom);
77 :
78 1 : return 0;
79 : }
80 :
81 2 : int RectIntersect(const struct Rect *a, const struct Rect *b, struct Rect *i)
82 : {
83 : /* Fast rejects */
84 2 : if (a->bottom < b->top)
85 : {
86 1 : return RECT_NO_INTERSECT;
87 : }
88 1 : if (a->right < b->left)
89 : {
90 0 : return RECT_NO_INTERSECT;
91 : }
92 1 : if (a->top > b->bottom)
93 : {
94 0 : return RECT_NO_INTERSECT;
95 : }
96 1 : if (a->left > b->right)
97 : {
98 0 : return RECT_NO_INTERSECT;
99 : }
100 :
101 1 : i->left = max(a->left, b->left);
102 1 : i->top = max(a->top, b->top);
103 1 : i->right = min(a->right, b->right);
104 1 : i->bottom = min(a->bottom, b->bottom);
105 :
106 1 : return RECT_INTERSECT;
107 : }
108 :
109 0 : void ConvertRect(const struct Rect *rect, int *x, int *y, int *w, int *h)
110 : {
111 0 : *x = rect->left;
112 0 : *y = rect->top;
113 0 : *w = rect->right - rect->left + 1;
114 0 : *h = rect->bottom - rect->top + 1;
115 0 : }
116 :
117 0 : void TranslateRect(struct Rect *rect, int x, int y)
118 : {
119 0 : rect->left += x;
120 0 : rect->top += y;
121 0 : rect->right += x;
122 0 : rect->bottom += y;
123 0 : }
124 :
125 : #if 0
126 : int PushClip(struct Rect *rect, const struct Rect *clip)
127 : {
128 : /* Clip rect to clip */
129 : }
130 :
131 : int PopClip(struct Rect *rect, const struct Rect *clip)
132 : {
133 : /* Restore previously pushed onto clip */
134 : }
135 : #endif
136 :
137 18 : int ClipRect(struct Rect *rect, const struct Rect *clip)
138 : {
139 18 : int ret = CLIP_NO_CHANGE;
140 :
141 : /* Fast rejects */
142 18 : if (rect->bottom < clip->top)
143 : {
144 : #define DEBUG 0
145 : #if DEBUG
146 : SerialPrintf("Too high\n");
147 : #endif
148 3 : return CLIP_REJECTED;
149 : }
150 15 : if (rect->right < clip->left)
151 : {
152 : #if DEBUG
153 : SerialPrintf("Too far left\n");
154 : #endif
155 2 : return CLIP_REJECTED;
156 : }
157 13 : if (rect->top > clip->bottom)
158 : {
159 : #if DEBUG
160 : SerialPrintf("Too low\n");
161 : #endif
162 1 : return CLIP_REJECTED;
163 : }
164 12 : if (rect->left > clip->right)
165 : {
166 : #if DEBUG
167 : SerialPrintf("Too far right\n");
168 : #endif
169 2 : return CLIP_REJECTED;
170 : }
171 :
172 : /* Clips */
173 10 : if (rect->top < clip->top)
174 : {
175 3 : rect->top = clip->top;
176 3 : ret = CLIP_CLIPPED;
177 : }
178 10 : if (rect->left < clip->left)
179 : {
180 3 : rect->left = clip->left;
181 3 : ret = CLIP_CLIPPED;
182 : }
183 10 : if (rect->right > clip->right)
184 : {
185 4 : rect->right = clip->right;
186 4 : ret = CLIP_CLIPPED;
187 : }
188 10 : if (rect->bottom > clip->bottom)
189 : {
190 4 : rect->bottom = clip->bottom;
191 4 : ret = CLIP_CLIPPED;
192 : }
193 :
194 10 : return ret;
195 : #if WE_COULD_USE_INTERSECT
196 : int ret;
197 :
198 : ret = RectIntersect(rect, clip, rect);
199 : if (ret == RECT_INTERSECT)
200 : {
201 : return CLIP_CLIPPED;
202 : }
203 :
204 : return CLIP_REJECTED;
205 : #endif
206 : }
207 :
208 1 : int ClipRectAdjust(struct Rect *dst, struct Rect *src, const struct Rect *clip)
209 : {
210 : int ret;
211 :
212 : /* Clip the dst rect based on the clipping rect. */
213 : /* Adjust the src rect based on how the dst rect was clipped. */
214 :
215 : struct Rect orig;
216 :
217 : /* Adjust dst clipping */
218 1 : orig = *dst;
219 1 : ret = ClipRect(dst, clip);
220 1 : if (ret == CLIP_REJECTED)
221 : {
222 0 : return CLIP_REJECTED;
223 : }
224 :
225 : /* Adjust src based on dst clipping */
226 1 : src->left += dst->left - orig.left; /* new_val - orig_val */
227 1 : src->top += dst->top - orig.top; /* new_val - orig_val */
228 1 : src->right -= (orig.right - dst->right);
229 1 : src->bottom -= (orig.bottom - dst->bottom);
230 :
231 1 : return CLIP_CLIPPED;
232 : }
|