forked from ghaerr/microwindows
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevclip2.c
More file actions
289 lines (264 loc) · 8.23 KB
/
Copy pathdevclip2.c
File metadata and controls
289 lines (264 loc) · 8.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
/*
* Copyright (c) 2000, 2010 Greg Haerr <greg@censoft.com>
* Copyright (c) 1991 David I. Bell
*
* DYNAMICREGIONS Device-independent routines to set clipping regions.
*/
#include <stdlib.h>
#include "device.h"
/* Clip cache rectangle information.
* After calling GdClipPoint, this rectangle is guaranteed to contain the
* specified point (among others), and all points in the rectangle are
* plottable or not according to the value of clipresult.
*/
MWCOORD clipminx; /* minimum x value of cache rectangle */
MWCOORD clipminy; /* minimum y value of cache rectangle */
MWCOORD clipmaxx; /* maximum x value of cache rectangle */
MWCOORD clipmaxy; /* maximum y value of cache rectangle */
static MWBOOL clipresult; /* whether clip rectangle is plottable */
MWCLIPREGION *clipregion = NULL;
/**
* Set a clip region for future drawing actions.
* Each pixel will be drawn only if lies in one or more of the contained
* clip rectangles. All clip rectangles are modified
* if necessary to lie within the device area. Call only after device
* has been initialized.
*
* @param psd Drawing surface.
* @param reg New clipping region.
*/
void
GdSetClipRegion(PSD psd, MWCLIPREGION *reg)
{
if(clipregion)
GdDestroyRegion(clipregion);
if(!reg)
reg = GdAllocRegion();
clipregion = reg;
#if 0
MWRECT rc;
/* Copy the clip table to our own static array, modifying each
* rectangle as necesary to fit within the device area. If the clip
* rectangle lies entirely outside of the device area, then skip it.
*/
while (count-- > 0) {
MWCLIPRECT cr;
MWCLIPRECT *rp = &cr;
*rp = *table++;
if (rp->x < 0) {
rp->width += rp->x;
rp->x = 0;
}
if (rp->y < 0) {
rp->height += rp->y;
rp->y = 0;
}
if ((rp->x >= psd->xvirtres) || (rp->width <= 0) ||
(rp->y >= psd->yvirtres) || (rp->height <= 0))
continue;
if (rp->x + rp->width > psd->xvirtres)
rp->width = psd->xvirtres - rp->x;
if (rp->y + rp->height > psd->yvirtres)
rp->height = psd->yvirtres - rp->y;
rc.left = rp->x;
rc.top = rp->y;
rc.right = rp->x+rp->width;
rc.bottom = rp->y+rp->height;
GdUnionRectWithRegion(&rc, clipregion);
}
#endif
/* If there were no surviving clip rectangles, then set the clip
* cache to prevent all drawing.
*/
if (clipregion->numRects == 0) {
clipminx = MIN_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return;
}
/* There was at least one valid clip rectangle. Default the clip
* cache to be the first clip rectangle.
*/
clipminx = clipregion->rects[0].left;
clipminy = clipregion->rects[0].top;
clipmaxx = clipregion->rects[0].right - 1;
clipmaxy = clipregion->rects[0].bottom - 1;
clipresult = TRUE;
}
/**
* Check a point against the list of clip rectangles.
* Returns TRUE if the point is within one or more rectangles and thus
* can be plotted, or FALSE if the point is not within any rectangle and
* thus cannot be plotted. Also remembers the coordinates of a clip cache
* rectangle containing the specified point such that every point in the
* rectangle would give the same result. By examining this clip cache
* rectangle after a call to this routine, the caller can efficiently
* check many nearby points without needing any further calls. If the
* point lies within the cursor, then the cursor is removed.
*
* @param psd Drawing surface
* @param x X-co-ordinate
* @param y Y-co-ordinate
* @return TRUE iff the point is visible.
*/
MWBOOL
GdClipPoint(PSD psd,MWCOORD x,MWCOORD y)
{
int count;
MWRECT *rp;
MWCOORD temp;
/* First see whether the point lies within the current clip cache
* rectangle. If so, then we already know the result.
*/
if ((x >= clipminx) && (x <= clipmaxx) &&
(y >= clipminy) && (y <= clipmaxy)) {
if (clipresult) GdCheckCursor(psd, x, y, x, y);
return clipresult;
}
/* If the point is outside of the screen area, then it is not
* plottable, and the clip cache rectangle is the whole half-plane
* outside of the screen area.
*/
if (x < 0) {
clipminx = MIN_MWCOORD;
clipmaxx = -1;
clipminy = MIN_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
if (y < 0) {
clipminx = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxy = -1;
clipresult = FALSE;
return FALSE;
}
if (x >= psd->xvirtres) {
clipminx = psd->xvirtres;
clipmaxx = MAX_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
if (y >= psd->yvirtres) {
clipminx = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipminy = psd->yvirtres;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
/* The point is within the screen area. If there are no clip
* rectangles, then the point is plottable and the rectangle is the
* whole screen.
*/
count = clipregion->numRects;
if (count <= 0) {
clipminx = 0;
clipmaxx = psd->xvirtres - 1;
clipminy = 0;
clipmaxy = psd->yvirtres - 1;
clipresult = TRUE;
GdCheckCursor(psd, x, y, x, y);
return TRUE;
}
/* We need to scan the list of clip rectangles to calculate a new
* clip cache rectangle containing this point, and the result. First
* see if the point lies within any of the clip rectangles. If so,
* then it is plottable and use that clip rectangle as the cache
* rectangle. This is not necessarily the best result, but works ok
* and is fast.
*/
for (rp = clipregion->rects; count-- > 0; rp++) {
if ((x >= rp->left) && (y >= rp->top) && (x < rp->right) && (y < rp->bottom)) {
clipminx = rp->left;
clipminy = rp->top;
clipmaxx = rp->right - 1;
clipmaxy = rp->bottom - 1;
clipresult = TRUE;
GdCheckCursor(psd, x, y, x, y);
return TRUE;
}
}
/* The point is not plottable. Scan the clip rectangles again to
* determine a rectangle containing more non-plottable points.
* Simply pick the largest rectangle whose area doesn't contain any
* of the same coordinates as appropriate sides of the clip
* rectangles. This is not necessarily the best result, but works ok
* and is fast.
*/
clipminx = MIN_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipmaxy = MAX_MWCOORD;
count = clipregion->numRects;
for (rp = clipregion->rects; count-- > 0; rp++) {
if ((x < rp->left) && (rp->left <= clipmaxx)) clipmaxx = rp->left - 1;
temp = rp->right - 1;
if ((x > temp) && (temp >= clipminx)) clipminx = temp + 1;
if ((y < rp->top) && (rp->top <= clipmaxy)) clipmaxy = rp->top - 1;
temp = rp->bottom - 1;
if ((y > temp) && (temp >= clipminy)) clipminy = temp + 1;
}
clipresult = FALSE;
return FALSE;
}
/**
* Check the area determined by the specified pair of points against the
* list of clip rectangles. The area will either be totally visible,
* totally invisible, or possibly partially visible. This routine updates
* the clip cache rectangle, and returns one of the following values:
* CLIP_VISIBLE The whole rectangle is visible
* CLIP_INVISIBLE The whole rectangle is invisible
* CLIP_PARTIAL The rectangle may be partially visible
* In the case that the area is totally visible, the cursor is removed
* if it overlaps the clip area.
*
* @param psd Drawing surface
* @param x1 Left edge of rectangle to check
* @param y1 Top edge of rectangle to check
* @param x2 Right edge of rectangle to check
* @param y2 Bottom edge of rectangle to check
* @return CLIP_VISIBLE, CLIP_INVISIBLE, or CLIP_PARTIAL
*/
int
GdClipArea(PSD psd,MWCOORD x1, MWCOORD y1, MWCOORD x2, MWCOORD y2)
{
if ((x1 < clipminx) || (x1 > clipmaxx) || (y1 < clipminy) || (y1 > clipmaxy))
GdClipPoint(psd, x1, y1);
if ((x2 >= clipminx) && (x2 <= clipmaxx) && (y2 >= clipminy) && (y2 <= clipmaxy)) {
if (!clipresult) return CLIP_INVISIBLE;
GdCheckCursor(psd, x1, y1, x2, y2);
return CLIP_VISIBLE;
}
return CLIP_PARTIAL;
}
#if DEBUG
void
GdPrintClipRects(PMWBLITPARMS gc)
{
extern MWCLIPREGION *clipregion;
MWRECT *prc = clipregion->rects;
int count = clipregion->numRects;
int n = 1;
if (gc)
DPRINTF("Clip rects (%d) for window draw %d,%d %d,%d\n",
count, gc->dstx, gc->dsty, gc->width, gc->height);
while (count-- > 0) {
MWCOORD rx1, rx2, ry1, ry2, rw, rh;
rx1 = prc->left;
ry1 = prc->top;
rx2 = prc->right;
ry2 = prc->bottom;
rw = rx2 - rx1;
rh = ry2 - ry1;
DPRINTF("R%03d %d,%d %d,%d\n", n++, rx1, ry1, rw, rh);
prc++;
}
}
#endif