/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __DIRECTFB_UTIL_H__ #define __DIRECTFB_UTIL_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif #include #include #include bool dfb_region_intersect( DFBRegion *region, int x1, int y1, int x2, int y2 ); bool dfb_region_region_intersect( DFBRegion *region, const DFBRegion *clip ); bool dfb_region_rectangle_intersect( DFBRegion *region, const DFBRectangle *rect ); bool dfb_unsafe_region_intersect( DFBRegion *region, int x1, int y1, int x2, int y2 ); bool dfb_unsafe_region_rectangle_intersect( DFBRegion *region, const DFBRectangle *rect ); bool dfb_rectangle_intersect_by_unsafe_region( DFBRectangle *rectangle, DFBRegion *region ); bool dfb_rectangle_intersect_by_region( DFBRectangle *rectangle, const DFBRegion *region ); bool dfb_rectangle_intersect( DFBRectangle *rectangle, const DFBRectangle *clip ); /* returns the result in the first rectangle */ void dfb_rectangle_union ( DFBRectangle *rect1, const DFBRectangle *rect2 ); #define DFB_RECTANGLE_ASSERT(r) \ do { \ D_ASSERT( (r) != NULL ); \ D_ASSERT( (r)->w >= 0 ); \ D_ASSERT( (r)->h >= 0 ); \ } while (0) #define DFB_RECTANGLE_ASSERT_IF(r) \ do { \ if ((r) != NULL) { \ D_ASSERT( (r)->w >= 0 ); \ D_ASSERT( (r)->h >= 0 ); \ } \ } while (0) #define DFB_RECTANGLE_VALS(r) (r)->x, (r)->y, (r)->w, (r)->h #define DFB_RECTANGLE_VALS_FROM_REGION(r) (r)->x1, (r)->y1, (r)->x2-(r)->x1+1, (r)->y2-(r)->y1+1 #define DFB_RECTANGLE_INIT_FROM_REGION(r) (DFBRectangle){ DFB_RECTANGLE_VALS_FROM_REGION(r) } #define DFB_RECTANGLE_CONTAINS_POINT(r,X,Y) (((X) >= (r)->x) && ((X) < (r)->x + (r)->w) && \ ((Y) >= (r)->y) && ((Y) < (r)->y + (r)->h)) #define DFB_RECTANGLES_DEBUG_AT( Domain, rects, num ) \ do { \ unsigned int i; \ \ for (i=0; i<(num); i++) \ D_DEBUG_AT( Domain, " -> [%2d] %4d,%4d-%4dx%4d\n", i, DFB_RECTANGLE_VALS(&(rects)[i]) ); \ } while (0) #define DFB_TRIANGLE_VALS(t) (t)->x1, (t)->y1, (t)->x2, (t)->y2, (t)->x3, (t)->y3 #define DFB_COLORKEY_VALS(c) (c)->r, (c)->g, (c)->b, (c)->index #define DFB_REGION_CHECK(r) \ ((r) != NULL && \ (r)->x1 <= (r)->x2 && \ (r)->y1 <= (r)->y2) #define DFB_REGION_CHECK_IF(r) \ ((r) == NULL || \ ((r)->x1 <= (r)->x2 && \ (r)->y1 <= (r)->y2)) #define DFB_REGION_ASSERT(r) \ do { \ D_ASSERT( (r) != NULL ); \ D_ASSERT( (r)->x1 <= (r)->x2 ); \ D_ASSERT( (r)->y1 <= (r)->y2 ); \ } while (0) #define DFB_REGION_ASSERT_IF(r) \ do { \ if ((r) != NULL) { \ D_ASSERT( (r)->x1 <= (r)->x2 ); \ D_ASSERT( (r)->y1 <= (r)->y2 ); \ } \ } while (0) #define DFB_REGION_VALS(r) (r)->x1, (r)->y1, (r)->x2, (r)->y2 #define DFB_REGION_VALS_FROM_DIMENSION(d) 0, 0, (d)->w-1, (d)->h-1 #define DFB_REGION_INIT_FROM_DIMENSION(d) (DFBRegion){ DFB_REGION_VALS_FROM_DIMENSION(d) } #define DFB_REGION_VALS_FROM_RECTANGLE(r) (r)->x, (r)->y, (r)->x+(r)->w-1, (r)->y+(r)->h-1 #define DFB_REGION_INIT_FROM_RECTANGLE(r) (DFBRegion){ DFB_REGION_VALS_FROM_RECTANGLE(r) } #define DFB_REGION_VALS_FROM_RECTANGLE_VALS(x,y,w,h) (x), (y), (x)+(w)-1, (y)+(h)-1 #define DFB_REGION_INIT_FROM_RECTANGLE_VALS(x,y,w,h) (DFBRegion){ DFB_REGION_VALS_FROM_RECTANGLE_VALS(x,y,w,h) } #define DFB_REGION_VALS_TRANSLATED(r,x,y) (r)->x1 + x, (r)->y1 + y, (r)->x2 + x, (r)->y2 + y #define DFB_REGION_INIT_TRANSLATED(r,x,y) (DFBRegion){ DFB_REGION_VALS_TRANSLATED(r,x,y) } #define DFB_REGION_VALS_INTERSECTED(r,X1,Y1,X2,Y2) (r)->x1 > (X1) ? (r)->x1 : (X1), \ (r)->y1 > (Y1) ? (r)->y1 : (Y1), \ (r)->x2 < (X2) ? (r)->x2 : (X2), \ (r)->y2 < (Y2) ? (r)->y2 : (Y2) #define DFB_REGION_INIT_INTERSECTED(r,X1,Y1,X2,Y2) (DFBRegion){ DFB_REGION_VALS_INTERSECTED(r,X1,Y1,X2,Y2) } #define DFB_REGION_CONTAINS_POINT(r,X,Y) (((X) >= (r)->x1) && ((X) <= (r)->x2) && \ ((Y) >= (r)->y1) && ((Y) <= (r)->y2)) static inline void dfb_rectangle_from_region( DFBRectangle *rect, const DFBRegion *region ) { D_ASSERT( rect != NULL ); DFB_REGION_ASSERT( region ); rect->x = region->x1; rect->y = region->y1; rect->w = region->x2 - region->x1 + 1; rect->h = region->y2 - region->y1 + 1; } static inline void dfb_rectangle_from_rectangle_plus_insets( DFBRectangle *rect, const DFBRectangle *inner, const DFBInsets *insets ) { D_ASSERT( rect != NULL ); D_ASSERT( insets != NULL ); DFB_RECTANGLE_ASSERT( inner ); rect->x = inner->x - insets->l; rect->y = inner->y - insets->t; rect->w = inner->w + insets->l + insets->r; rect->h = inner->h + insets->t + insets->b; } static inline void dfb_region_from_rectangle( DFBRegion *region, const DFBRectangle *rect ) { D_ASSERT( region != NULL ); DFB_RECTANGLE_ASSERT( rect ); D_ASSERT( rect->w > 0 ); D_ASSERT( rect->h > 0 ); region->x1 = rect->x; region->y1 = rect->y; region->x2 = rect->x + rect->w - 1; region->y2 = rect->y + rect->h - 1; } static inline void dfb_region_from_rotated( DFBRegion *region, const DFBRegion *from, const DFBDimension *size, int rotation ) { D_ASSERT( region != NULL ); DFB_REGION_ASSERT( from ); D_ASSERT( size != NULL ); D_ASSERT( size->w > 0 ); D_ASSERT( size->h > 0 ); D_ASSUME( rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270 ); switch (rotation) { default: D_BUG( "invalid rotation %d", rotation ); case 0: *region = *from; break; case 90: region->x1 = from->y1; region->y1 = size->w - from->x2 - 1; region->x2 = from->y2; region->y2 = size->w - from->x1 - 1; break; case 180: region->x1 = size->w - from->x2 - 1; region->y1 = size->h - from->y2 - 1; region->x2 = size->w - from->x1 - 1; region->y2 = size->h - from->y1 - 1; break; case 270: region->x1 = size->h - from->y2 - 1; region->y1 = from->x1; region->x2 = size->h - from->y1 - 1; region->y2 = from->x2; break; } DFB_REGION_ASSERT( region ); } static inline void dfb_rectangle_from_rotated( DFBRectangle *rectangle, const DFBRectangle *from, const DFBDimension *size, int rotation ) { D_ASSERT( rectangle != NULL ); DFB_RECTANGLE_ASSERT( from ); D_ASSERT( size != NULL ); D_ASSERT( size->w > 0 ); D_ASSERT( size->h > 0 ); D_ASSUME( rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270 ); switch (rotation) { default: D_BUG( "invalid rotation %d", rotation ); case 0: *rectangle = *from; break; case 90: rectangle->x = from->y; rectangle->y = size->w - from->x - from->w; rectangle->w = from->h; rectangle->h = from->w; break; case 180: rectangle->x = size->w - from->x - from->w; rectangle->y = size->h - from->y - from->h; rectangle->w = from->w; rectangle->h = from->h; break; case 270: rectangle->x = size->h - from->y - from->h; rectangle->y = from->x; rectangle->w = from->h; rectangle->h = from->w; break; } DFB_RECTANGLE_ASSERT( rectangle ); } static inline void dfb_point_from_rotated_region( DFBPoint *point, const DFBRegion *from, const DFBDimension *size, int rotation ) { D_ASSERT( point != NULL ); DFB_REGION_ASSERT( from ); D_ASSERT( size != NULL ); D_ASSERT( size->w > 0 ); D_ASSERT( size->h > 0 ); D_ASSUME( rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270 ); switch (rotation) { default: D_BUG( "invalid rotation %d", rotation ); case 0: point->x = from->x1; point->y = from->y1; break; case 90: point->x = from->y1; point->y = size->w - from->x2 - 1; break; case 180: point->x = size->w - from->x2 - 1; point->y = size->h - from->y2 - 1; break; case 270: point->x = size->h - from->y2 - 1; point->y = from->x1; break; } D_ASSERT( point->x >= 0 ); D_ASSERT( point->y >= 0 ); D_ASSERT( point->x < size->w ); D_ASSERT( point->y < size->h ); } static inline void dfb_rectangle_translate( DFBRectangle *rect, int dx, int dy ) { DFB_RECTANGLE_ASSERT( rect ); rect->x += dx; rect->y += dy; } static inline void dfb_region_translate( DFBRegion *region, int dx, int dy ) { DFB_REGION_ASSERT( region ); region->x1 += dx; region->y1 += dy; region->x2 += dx; region->y2 += dy; } static inline void dfb_rectangle_resize( DFBRectangle *rect, int width, int height ) { DFB_RECTANGLE_ASSERT( rect ); D_ASSERT( width >= 0 ); D_ASSERT( height >= 0 ); rect->w = width; rect->h = height; } static inline void dfb_region_resize( DFBRegion *region, int width, int height ) { DFB_REGION_ASSERT( region ); D_ASSERT( width >= 0 ); D_ASSERT( height >= 0 ); region->x2 = region->x1 + width - 1; region->y2 = region->y1 + height - 1; } static inline bool dfb_region_intersects( const DFBRegion *region, int x1, int y1, int x2, int y2 ) { DFB_REGION_ASSERT( region ); D_ASSERT( x1 <= x2 ); D_ASSERT( y1 <= y2 ); return (region->x1 <= x2 && region->y1 <= y2 && region->x2 >= x1 && region->y2 >= y1); } static inline bool dfb_region_region_intersects( const DFBRegion *region, const DFBRegion *other ) { DFB_REGION_ASSERT( region ); DFB_REGION_ASSERT( other ); return (region->x1 <= other->x2 && region->y1 <= other->y2 && region->x2 >= other->x1 && region->y2 >= other->y1); } static inline bool dfb_region_region_extends( const DFBRegion *a, const DFBRegion *b ) { if (a->x1 == b->x1 && a->x2 == b->x2) return (a->y1 == b->y2 - 1) || (a->y2 == b->y1 - 1); if (a->y1 == b->y1 && a->y2 == b->y2) return (a->x1 == b->x2 - 1) || (a->x2 == b->x1 - 1); return false; } static inline void dfb_region_region_union( DFBRegion *region, const DFBRegion *other ) { DFB_REGION_ASSERT( region ); DFB_REGION_ASSERT( other ); if (region->x1 > other->x1) region->x1 = other->x1; if (region->y1 > other->y1) region->y1 = other->y1; if (region->x2 < other->x2) region->x2 = other->x2; if (region->y2 < other->y2) region->y2 = other->y2; } static inline bool dfb_rectangle_region_intersects( const DFBRectangle *rect, const DFBRegion *region ) { DFB_RECTANGLE_ASSERT( rect ); DFB_REGION_ASSERT( region ); return (rect->x <= region->x2 && rect->y <= region->y2 && rect->x + rect->w > region->x1 && rect->y + rect->h > region->y1); } static inline void dfb_region_clip( DFBRegion *region, int x1, int y1, int x2, int y2 ) { DFB_REGION_ASSERT( region ); D_ASSERT( dfb_region_intersects( region, x1, y1, x2, y2 ) ); if (region->x1 < x1) region->x1 = x1; if (region->y1 < y1) region->y1 = y1; if (region->x2 > x2) region->x2 = x2; if (region->y2 > y2) region->y2 = y2; } static inline void dfb_rectangle_subtract( DFBRectangle *rect, const DFBInsets *insets ) { D_ASSERT( rect != NULL ); D_ASSERT( insets != NULL ); rect->x += insets->l; rect->y += insets->t; rect->w -= insets->l + insets->r; rect->h -= insets->t + insets->b; if (rect->w <= 0 || rect->h <= 0) rect->w = rect->h = 0; } /* * Compute line segment intersection. * Return true if intersection point exists within the given segment. */ static inline bool dfb_line_segment_intersect( const DFBRegion *line, const DFBRegion *seg, int *x, int *y ) { int x1, x2, x3, x4; int y1, y2, y3, y4; int num, den; D_ASSERT( line != NULL ); D_ASSERT( seg != NULL ); x1 = seg->x1; y1 = seg->y1; x2 = seg->y2; y2 = seg->y2; x3 = line->x1; y3 = line->y1; x4 = line->x2; y4 = line->y2; num = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); den = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); if (!den) /* parallel */ return false; if (num && ((num < 0) != (den < 0) || abs(num) > abs(den))) /* not within segment */ return false; if (x) *x = (s64)(x2 - x1) * num / den + x1; if (y) *y = (s64)(y2 - y1) * num / den + y1; return true; } /* * Copied declaration of DFBPixelFormatName from directfb_strings.h */ extern const struct DFBPixelFormatName dfb_pixelformat_names[]; const char *dfb_input_event_type_name ( DFBInputEventType type ); const char *dfb_pixelformat_name ( DFBSurfacePixelFormat format ); const char *dfb_window_event_type_name( DFBWindowEventType type ); typedef struct { int magic; DFBRegion *regions; int max_regions; int num_regions; DFBRegion bounding; } DFBUpdates; #define DFB_UPDATES_ASSERT(updates) \ do { \ D_MAGIC_ASSERT( updates, DFBUpdates ); \ D_ASSERT( (updates)->regions != NULL ); \ D_ASSERT( (updates)->max_regions > 0 ); \ D_ASSERT( (updates)->num_regions <= (updates)->max_regions ); \ } while (0) void dfb_updates_init( DFBUpdates *updates, DFBRegion *regions, int max_regions ); void dfb_updates_add ( DFBUpdates *updates, const DFBRegion *region ); void dfb_updates_stat( DFBUpdates *updates, int *ret_total, int *ret_bounding ); void dfb_updates_get_rectangles( DFBUpdates *updates, DFBRectangle *ret_rects, int *ret_num ); static inline void dfb_updates_add_rect( DFBUpdates *updates, int x, int y, int w, int h ) { DFBRegion region = DFB_REGION_INIT_FROM_RECTANGLE_VALS( x, y, w, h ); dfb_updates_add( updates, ®ion ); } static inline void dfb_updates_reset( DFBUpdates *updates ) { D_MAGIC_ASSERT( updates, DFBUpdates ); updates->num_regions = 0; } static inline void dfb_updates_deinit( DFBUpdates *updates ) { D_MAGIC_ASSERT( updates, DFBUpdates ); D_MAGIC_CLEAR( updates ); } #ifdef __cplusplus } #endif #endif