1 /*
2 (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
3 (c) Copyright 2000-2004 Convergence (integrated media) GmbH
4
5 All rights reserved.
6
7 Written by Denis Oliver Kropp <dok@directfb.org>,
8 Andreas Hundt <andi@fischlustig.de>,
9 Sven Neumann <neo@directfb.org>,
10 Ville Syrjälä <syrjala@sci.fi> and
11 Claudio Ciccani <klan@users.sf.net>.
12
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2 of the License, or (at your option) any later version.
17
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
22
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the
25 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 Boston, MA 02111-1307, USA.
27 */
28
29 #include <config.h>
30
31 #include <string.h>
32
33 #include <directfb.h>
34
35 #include <direct/util.h>
36
37 #include <misc/util.h>
38
39 #include <gfx/clip.h>
40 #include <gfx/util.h>
41
42 D_DEBUG_DOMAIN( Core_Clipping, "Core/Clipping", "DirectFB Software Clipping" );
43
44 #define REGION_CODE(x,y,cx1,cx2,cy1,cy2) ( ( (y) > (cy2) ? 8 : 0) | \
45 ( (y) < (cy1) ? 4 : 0) | \
46 ( (x) > (cx2) ? 2 : 0) | \
47 ( (x) < (cx1) ? 1 : 0) )
48
49
50 DFBBoolean
dfb_clip_line(const DFBRegion * clip,DFBRegion * line)51 dfb_clip_line( const DFBRegion *clip, DFBRegion *line )
52 {
53 unsigned char region_code1 = REGION_CODE( line->x1, line->y1,
54 clip->x1,
55 clip->x2,
56 clip->y1,
57 clip->y2 );
58
59 unsigned char region_code2 = REGION_CODE( line->x2, line->y2,
60 clip->x1,
61 clip->x2,
62 clip->y1,
63 clip->y2 );
64
65 while (region_code1 | region_code2) {
66 /* line completely outside the clipping rectangle */
67 if (region_code1 & region_code2)
68 return DFB_FALSE;
69
70
71 if (region_code1) {
72 if (region_code1 & 8) { /* divide line at bottom*/
73 line->x1 = line->x1 +(line->x2-line->x1) * (clip->y2 - line->y1) / (line->y2-line->y1);
74 line->y1 = clip->y2;
75 }
76 else
77 if (region_code1 & 4) { /* divide line at top*/
78 line->x1 = line->x1 +(line->x2-line->x1) * (clip->y1 - line->y1) / (line->y2-line->y1);
79 line->y1 = clip->y1;
80 }
81 else
82 if (region_code1 & 2) { /* divide line at right*/
83 line->y1 = line->y1 +(line->y2-line->y1) * (clip->x2 - line->x1) / (line->x2-line->x1);
84 line->x1 = clip->x2;
85 }
86 else
87 if (region_code1 & 1) { /* divide line at right*/
88 line->y1 = line->y1 +(line->y2-line->y1) * (clip->x1 - line->x1) / (line->x2-line->x1);
89 line->x1 = clip->x1;
90 }
91 region_code1 = REGION_CODE( line->x1, line->y1,
92 clip->x1,
93 clip->x2,
94 clip->y1,
95 clip->y2 );
96 }
97 else {
98 if (region_code2 & 8) { /* divide line at bottom*/
99 line->x2 = line->x1 +(line->x2-line->x1) * (clip->y2 - line->y1) / (line->y2-line->y1);
100 line->y2 = clip->y2;
101 }
102 else
103 if (region_code2 & 4) { /* divide line at top*/
104 line->x2 = line->x1 +(line->x2-line->x1) * (clip->y1 - line->y1) / (line->y2-line->y1);
105 line->y2 = clip->y1;
106 }
107 else
108 if (region_code2 & 2) { /* divide line at right*/
109 line->y2 = line->y1 +(line->y2-line->y1) * (clip->x2 - line->x1) / (line->x2-line->x1);
110 line->x2 = clip->x2;
111 }
112 else
113 if (region_code2 & 1) { /* divide line at right*/
114 line->y2 = line->y1 +(line->y2-line->y1) * (clip->x1 - line->x1) / (line->x2-line->x1);
115 line->x2 = clip->x1;
116 }
117 region_code2 = REGION_CODE( line->x2, line->y2, clip->x1,
118 clip->x2,
119 clip->y1,
120 clip->y2 );
121 }
122 }
123
124 /* successfully clipped or clipping not neccessary */
125 return DFB_TRUE;
126 }
127
128 DFBEdgeFlags
dfb_clip_edges(const DFBRegion * clip,DFBRectangle * rect)129 dfb_clip_edges( const DFBRegion *clip, DFBRectangle *rect )
130 {
131 DFBEdgeFlags flags = DFEF_ALL;
132
133 if ((clip->x1 >= rect->x + rect->w) ||
134 (clip->x2 < rect->x) ||
135 (clip->y1 >= rect->y + rect->h) ||
136 (clip->y2 < rect->y))
137 return DFEF_NONE;
138
139 if (clip->x1 > rect->x) {
140 rect->w += rect->x - clip->x1;
141 rect->x = clip->x1;
142
143 flags &= ~DFEF_LEFT;
144 }
145
146 if (clip->y1 > rect->y) {
147 rect->h += rect->y - clip->y1;
148 rect->y = clip->y1;
149
150 flags &= ~DFEF_TOP;
151 }
152
153 if (clip->x2 < rect->x + rect->w - 1) {
154 rect->w = clip->x2 - rect->x + 1;
155
156 flags &= ~DFEF_RIGHT;
157 }
158
159 if (clip->y2 < rect->y + rect->h - 1) {
160 rect->h = clip->y2 - rect->y + 1;
161
162 flags &= ~DFEF_BOTTOM;
163 }
164
165 return flags;
166 }
167
168 DFBBoolean
dfb_clip_rectangle(const DFBRegion * clip,DFBRectangle * rect)169 dfb_clip_rectangle( const DFBRegion *clip, DFBRectangle *rect )
170 {
171 if ((clip->x1 >= rect->x + rect->w) ||
172 (clip->x2 < rect->x) ||
173 (clip->y1 >= rect->y + rect->h) ||
174 (clip->y2 < rect->y))
175 return DFB_FALSE;
176
177 if (clip->x1 > rect->x) {
178 rect->w += rect->x - clip->x1;
179 rect->x = clip->x1;
180 }
181
182 if (clip->y1 > rect->y) {
183 rect->h += rect->y - clip->y1;
184 rect->y = clip->y1;
185 }
186
187 if (clip->x2 < rect->x + rect->w - 1)
188 rect->w = clip->x2 - rect->x + 1;
189
190 if (clip->y2 < rect->y + rect->h - 1)
191 rect->h = clip->y2 - rect->y + 1;
192
193 return DFB_TRUE;
194 }
195
196 DFBBoolean
dfb_clip_triangle_precheck(const DFBRegion * clip,const DFBTriangle * tri)197 dfb_clip_triangle_precheck( const DFBRegion *clip, const DFBTriangle *tri )
198 {
199 int x, y, w, h;
200
201 x = MIN (MIN (tri->x1, tri->x2), tri->x3);
202 y = MIN (MIN (tri->y1, tri->y2), tri->y3);
203 w = MAX (MAX (tri->x1, tri->x2), tri->x3) - x;
204 h = MAX (MAX (tri->y1, tri->y2), tri->y3) - y;
205
206 if (clip->x1 > x ||
207 clip->x2 < x + w ||
208 clip->y1 > y ||
209 clip->y2 < y + h)
210 return DFB_FALSE;
211
212 return DFB_TRUE;
213 }
214
215 DFBBoolean
dfb_clip_triangle(const DFBRegion * clip,const DFBTriangle * tri,DFBPoint p[6],int * num)216 dfb_clip_triangle( const DFBRegion *clip, const DFBTriangle *tri, DFBPoint p[6], int *num )
217 {
218 DFBRegion edges[3];
219 int num_edges;
220 int i, n;
221 DFBPoint p1 = {0, 0}, p2 = {0, 0};
222
223 /* Initialize edges. */
224 edges[0].x1 = tri->x1; edges[0].y1 = tri->y1;
225 edges[0].x2 = tri->x2; edges[0].y2 = tri->y2;
226 edges[1].x1 = tri->x2; edges[1].y1 = tri->y2;
227 edges[1].x2 = tri->x3; edges[1].y2 = tri->y3;
228 edges[2].x1 = tri->x3; edges[2].y1 = tri->y3;
229 edges[2].x2 = tri->x1; edges[2].y2 = tri->y1;
230 num_edges = 3;
231
232 for (i = 0; i < num_edges; i++) {
233 DFBRegion *reg = &edges[i];
234 DFBRegion line;
235 bool i1, i2;
236
237 /* Clip the edge to the clipping region. */
238 line = *reg;
239 if (dfb_clip_line( clip, &line )) {
240 *reg = line;
241 continue;
242 }
243
244 /* If the edge doesn't intersect clipping region, then
245 * intersect the edge with the diagonals of the clipping
246 * rectangle. If intersection point exits, add the nearest
247 * corner of the clipping region to the list of vertices.
248 */
249
250 /* Diagonal (x1,y1) (x2,y2). */
251 line = (DFBRegion) { clip->x1, clip->y1, clip->x2, clip->y2 };
252 i1 = dfb_line_segment_intersect( &line, reg, &p1.x, &p1.y );
253 if (i1) {
254 /* Get nearest corner. */
255 if (p1.x <= clip->x1 || p1.y <= clip->y1) {
256 p1.x = clip->x1;
257 p1.y = clip->y1;
258 } else {
259 p1.x = clip->x2;
260 p1.y = clip->y2;
261 }
262 }
263
264 /* Diagonal (x2,y1) (x1,y2). */
265 line = (DFBRegion) { clip->x2, clip->y1, clip->x1, clip->y2 };
266 i2 = dfb_line_segment_intersect( &line, reg, &p2.x, &p2.y );
267 if (i2) {
268 /* Get nearest corner. */
269 if (p2.x >= clip->x2 || p2.y <= clip->y1) {
270 p2.x = clip->x2;
271 p2.y = clip->y1;
272 } else {
273 p2.x = clip->x1;
274 p2.y = clip->y2;
275 }
276 }
277
278 if (i1 && i2) {
279 reg->x1 = p1.x;
280 reg->y1 = p1.y;
281 reg->x2 = p2.x;
282 reg->y2 = p2.y;
283 }
284 else if (i1) {
285 reg->x1 = reg->x2 = p1.x;
286 reg->y1 = reg->y2 = p1.y;
287 }
288 else if (i2) {
289 reg->x1 = reg->x2 = p2.x;
290 reg->y1 = reg->y2 = p2.y;
291 }
292 else {
293 /* Redudant edge. Remote it. */
294 memmove( reg, &edges[i+1], (num_edges-i-1) * sizeof(DFBRegion) );
295 num_edges--;
296 i--;
297 }
298 }
299
300 if (num_edges < 1) {
301 *num = 0;
302 return DFB_FALSE;
303 }
304
305 /* Get vertices from edges. */
306 p[0].x = edges[0].x1; p[0].y = edges[0].y1;
307 n = 1;
308 if (edges[0].x2 != edges[0].x1 || edges[0].y2 != edges[0].y1) {
309 p[1].x = edges[0].x2; p[1].y = edges[0].y2;
310 n++;
311 }
312
313 for (i = 1; i < num_edges; i++) {
314 if (edges[i].x1 != p[n-1].x || edges[i].y1 != p[n-1].y) {
315 p[n].x = edges[i].x1; p[n].y = edges[i].y1;
316 n++;
317 }
318 if (edges[i].x2 != p[n-1].x || edges[i].y2 != p[n-1].y) {
319 p[n].x = edges[i].x2; p[n].y = edges[i].y2;
320 n++;
321 }
322 }
323
324 if (p[n-1].x == p[0].x && p[n-1].y == p[0].y)
325 n--;
326
327 *num = n;
328
329 /* Actually fail if the number of vertices is below 3. */
330 return (n >= 3);
331 }
332
333
334 void
dfb_clip_blit(const DFBRegion * clip,DFBRectangle * srect,int * dx,int * dy)335 dfb_clip_blit( const DFBRegion *clip,
336 DFBRectangle *srect, int *dx, int *dy )
337 {
338 if (clip->x1 > *dx ) {
339 srect->w = MIN( (clip->x2 - clip->x1) + 1,
340 (*dx + srect->w) - clip->x1);
341
342 srect->x+= clip->x1 - *dx;
343 *dx = clip->x1;
344 }
345 else if (clip->x2 < *dx + srect->w - 1) {
346 srect->w = clip->x2 - *dx + 1;
347 }
348
349 if (clip->y1 > *dy ) {
350 srect->h = MIN( (clip->y2 - clip->y1) + 1,
351 (*dy + srect->h) - clip->y1);
352 srect->y+= clip->y1 - *dy;
353 *dy = clip->y1;
354 }
355 else if (clip->y2 < *dy + srect->h - 1) {
356 srect->h = clip->y2 - *dy + 1;
357 }
358 }
359
360 void
dfb_clip_stretchblit(const DFBRegion * clip,DFBRectangle * srect,DFBRectangle * drect)361 dfb_clip_stretchblit( const DFBRegion *clip,
362 DFBRectangle *srect, DFBRectangle *drect )
363 {
364 DFBRectangle orig_dst = *drect;
365
366 dfb_clip_rectangle( clip, drect );
367
368 if (drect->x != orig_dst.x)
369 srect->x += (int)( (drect->x - orig_dst.x) *
370 (srect->w / (float)orig_dst.w) );
371
372 if (drect->y != orig_dst.y)
373 srect->y += (int)( (drect->y - orig_dst.y) *
374 (srect->h / (float)orig_dst.h) );
375
376 if (drect->w != orig_dst.w)
377 srect->w = (int)( srect->w * (drect->w / (float)orig_dst.w) );
378
379 if (drect->h != orig_dst.h)
380 srect->h = (int)( srect->h * (drect->h / (float)orig_dst.h) );
381 }
382
383
384 void
dfb_clip_blit_flipped_rotated(const DFBRegion * clip,DFBRectangle * srect,DFBRectangle * drect,DFBSurfaceBlittingFlags flags)385 dfb_clip_blit_flipped_rotated( const DFBRegion *clip,
386 DFBRectangle *srect, DFBRectangle *drect, DFBSurfaceBlittingFlags flags )
387 {
388
389 DFBRegion dest = DFB_REGION_INIT_FROM_RECTANGLE( drect );
390 DFBRegion clipped = dest;
391
392 D_ASSERT( !(flags & (DSBLIT_ROTATE270 | DSBLIT_ROTATE180)) );
393
394 if (flags & DSBLIT_ROTATE90) {
395 D_ASSERT( srect->w == drect->h );
396 D_ASSERT( srect->h == drect->w );
397 }
398 else {
399 D_ASSERT( srect->w == drect->w );
400 D_ASSERT( srect->h == drect->h );
401 }
402
403 dfb_region_region_intersect( &clipped, clip );
404 dfb_rectangle_from_region( drect, &clipped );
405
406 switch (flags & (DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL | DSBLIT_ROTATE90)) {
407 case DSBLIT_NOFX:
408 srect->x += clipped.x1 - dest.x1;
409 srect->y += clipped.y1 - dest.y1;
410 break;
411 case DSBLIT_FLIP_HORIZONTAL:
412 srect->x += dest.x2 - clipped.x2;
413 srect->y += clipped.y1 - dest.y1;
414 break;
415 case DSBLIT_FLIP_VERTICAL:
416 srect->x += clipped.x1 - dest.x1;
417 srect->y += dest.y2 - clipped.y2;
418 break;
419 case DSBLIT_ROTATE90:
420 srect->x += dest.y2 - clipped.y2;
421 srect->y += clipped.x1 - dest.x1;
422 break;
423 case (DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL): // ROTATE180
424 srect->x += dest.x2 - clipped.x2;
425 srect->y += dest.y2 - clipped.y2;
426 break;
427 case (DSBLIT_ROTATE90 | DSBLIT_FLIP_VERTICAL | DSBLIT_FLIP_HORIZONTAL): // ROTATE270
428 srect->x += clipped.y1 - dest.y1;
429 srect->y += dest.x2 - clipped.x2;
430 break;
431 case (DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL):
432 srect->x += clipped.y1 - dest.y1;
433 srect->y += clipped.x1 - dest.x1;
434 break;
435 case (DSBLIT_ROTATE90 | DSBLIT_FLIP_VERTICAL):
436 srect->x += dest.y2 - clipped.y2;
437 srect->y += dest.x2 - clipped.x2;
438 break;
439 }
440
441 if (flags & DSBLIT_ROTATE90) {
442 srect->w = drect->h;
443 srect->h = drect->w;
444 }
445 else {
446 srect->w = drect->w;
447 srect->h = drect->h;
448 }
449
450 D_DEBUG_AT( Core_Clipping, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d\n",
451 DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) );
452 }
453