diff options
Diffstat (limited to 'libtwin/twin_pixmap.c')
-rw-r--r-- | libtwin/twin_pixmap.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/libtwin/twin_pixmap.c b/libtwin/twin_pixmap.c new file mode 100644 index 0000000..e056093 --- /dev/null +++ b/libtwin/twin_pixmap.c @@ -0,0 +1,346 @@ +/* + * Twin - A Tiny Window System + * Copyright © 2004 Keith Packard <keithp@keithp.com> + * All rights reserved. + * + * This Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Twin Library; see the file COPYING. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "twinint.h" + +twin_pixmap_t * +twin_pixmap_create (twin_format_t format, + twin_coord_t width, + twin_coord_t height) +{ + twin_coord_t stride = twin_bytes_per_pixel (format) * width; + twin_area_t space = (twin_area_t) stride * height; + twin_area_t size = sizeof (twin_pixmap_t) + space; + twin_pixmap_t *pixmap = malloc (size); + if (!pixmap) + return 0; + pixmap->screen = 0; + pixmap->up = 0; + pixmap->down = 0; + pixmap->x = pixmap->y = 0; + pixmap->format = format; + pixmap->width = width; + pixmap->height = height; + twin_matrix_identity(&pixmap->transform); + pixmap->clip.left = pixmap->clip.top = 0; + pixmap->clip.right = pixmap->width; + pixmap->clip.bottom = pixmap->height; + pixmap->origin_x = pixmap->origin_y = 0; + pixmap->stride = stride; + pixmap->disable = 0; + pixmap->p.v = pixmap + 1; + memset (pixmap->p.v, '\0', space); + return pixmap; +} + +twin_pixmap_t * +twin_pixmap_create_const (twin_format_t format, + twin_coord_t width, + twin_coord_t height, + twin_coord_t stride, + twin_pointer_t pixels) +{ + twin_pixmap_t *pixmap = malloc (sizeof (twin_pixmap_t)); + if (!pixmap) + return 0; + pixmap->screen = 0; + pixmap->up = 0; + pixmap->down = 0; + pixmap->x = pixmap->y = 0; + pixmap->format = format; + pixmap->width = width; + pixmap->height = height; + twin_matrix_identity(&pixmap->transform); + pixmap->clip.left = pixmap->clip.top = 0; + pixmap->clip.right = pixmap->width; + pixmap->clip.bottom = pixmap->height; + pixmap->origin_x = pixmap->origin_y = 0; + pixmap->stride = stride; + pixmap->disable = 0; + pixmap->p = pixels; + return pixmap; +} + +void +twin_pixmap_destroy (twin_pixmap_t *pixmap) +{ + if (pixmap->screen) + twin_pixmap_hide (pixmap); + free (pixmap); +} + +void +twin_pixmap_show (twin_pixmap_t *pixmap, + twin_screen_t *screen, + twin_pixmap_t *lower) +{ + if (pixmap->disable) + twin_screen_disable_update (screen); + + if (lower == pixmap) + lower = pixmap->down; + + if (pixmap->screen) + twin_pixmap_hide (pixmap); + + pixmap->screen = screen; + + if (lower) + { + pixmap->down = lower; + pixmap->up = lower->up; + lower->up = pixmap; + if (!pixmap->up) + screen->top = pixmap; + } + else + { + pixmap->down = NULL; + pixmap->up = screen->bottom; + screen->bottom = pixmap; + if (!pixmap->up) + screen->top = pixmap; + } + + twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); +} + +void +twin_pixmap_hide (twin_pixmap_t *pixmap) +{ + twin_screen_t *screen = pixmap->screen; + twin_pixmap_t **up, **down; + + if (!screen) + return; + + twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); + + if (pixmap->up) + down = &pixmap->up->down; + else + down = &screen->top; + + if (pixmap->down) + up = &pixmap->down->up; + else + up = &screen->bottom; + + *down = pixmap->down; + *up = pixmap->up; + + pixmap->screen = 0; + pixmap->up = 0; + pixmap->down = 0; + if (pixmap->disable) + twin_screen_enable_update (screen); +} + +twin_pointer_t +twin_pixmap_pointer (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y) +{ + twin_pointer_t p; + + p.b = (pixmap->p.b + + y * pixmap->stride + + x * twin_bytes_per_pixel(pixmap->format)); + return p; +} + +void +twin_pixmap_enable_update (twin_pixmap_t *pixmap) +{ + if (--pixmap->disable == 0) + { + if (pixmap->screen) + twin_screen_enable_update (pixmap->screen); + } +} + +void +twin_pixmap_disable_update (twin_pixmap_t *pixmap) +{ + if (pixmap->disable++ == 0) + { + if (pixmap->screen) + twin_screen_disable_update (pixmap->screen); + } +} + +void +twin_pixmap_set_origin (twin_pixmap_t *pixmap, + twin_coord_t ox, twin_coord_t oy) +{ + pixmap->origin_x = ox; + pixmap->origin_y = oy; +} + +void +twin_pixmap_offset (twin_pixmap_t *pixmap, + twin_coord_t offx, twin_coord_t offy) +{ + pixmap->origin_x += offx; + pixmap->origin_y += offy; +} + +void +twin_pixmap_get_origin (twin_pixmap_t *pixmap, + twin_coord_t *ox, twin_coord_t *oy) +{ + *ox = pixmap->origin_x; + *oy = pixmap->origin_y; +} + +void +twin_pixmap_origin_to_clip (twin_pixmap_t *pixmap) +{ + pixmap->origin_x = pixmap->clip.left; + pixmap->origin_y = pixmap->clip.top; +} + +void +twin_pixmap_clip (twin_pixmap_t *pixmap, + twin_coord_t left, twin_coord_t top, + twin_coord_t right, twin_coord_t bottom) +{ + left += pixmap->origin_x; + right += pixmap->origin_x; + top += pixmap->origin_y; + bottom += pixmap->origin_y; + + if (left > pixmap->clip.left) pixmap->clip.left = left; + if (top > pixmap->clip.top) pixmap->clip.top = top; + if (right < pixmap->clip.right) pixmap->clip.right = right; + if (bottom < pixmap->clip.bottom) pixmap->clip.bottom = bottom; + + if (pixmap->clip.left >= pixmap->clip.right) + pixmap->clip.right = pixmap->clip.left = 0; + if (pixmap->clip.top >= pixmap->clip.bottom) + pixmap->clip.bottom = pixmap->clip.top = 0; + + if (pixmap->clip.left < 0) + pixmap->clip.left = 0; + if (pixmap->clip.top < 0) + pixmap->clip.top = 0; + if (pixmap->clip.right > pixmap->width) + pixmap->clip.right = pixmap->width; + if (pixmap->clip.bottom > pixmap->height) + pixmap->clip.bottom = pixmap->height; +} + +void +twin_pixmap_set_clip (twin_pixmap_t *pixmap, twin_rect_t clip) +{ + twin_pixmap_clip (pixmap, + clip.left, clip.top, + clip.right, clip.bottom); +} + + +twin_rect_t +twin_pixmap_get_clip (twin_pixmap_t *pixmap) +{ + twin_rect_t clip = pixmap->clip; + + clip.left -= pixmap->origin_x; + clip.right -= pixmap->origin_x; + clip.top -= pixmap->origin_y; + clip.bottom -= pixmap->origin_y; + + return clip; +} + +twin_rect_t +twin_pixmap_save_clip (twin_pixmap_t *pixmap) +{ + return pixmap->clip; +} + +void +twin_pixmap_restore_clip (twin_pixmap_t *pixmap, twin_rect_t rect) +{ + pixmap->clip = rect; +} + +void +twin_pixmap_reset_clip (twin_pixmap_t *pixmap) +{ + pixmap->clip.left = 0; pixmap->clip.top = 0; + pixmap->clip.right = pixmap->width; pixmap->clip.bottom = pixmap->height; +} + +void +twin_pixmap_damage (twin_pixmap_t *pixmap, + twin_coord_t left, twin_coord_t top, + twin_coord_t right, twin_coord_t bottom) +{ + if (pixmap->screen) + twin_screen_damage (pixmap->screen, + left + pixmap->x, + top + pixmap->y, + right + pixmap->x, + bottom + pixmap->y); +} + +static twin_argb32_t +_twin_pixmap_fetch (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y) +{ + twin_pointer_t p = twin_pixmap_pointer (pixmap, x - pixmap->x, y - pixmap->y); + // XXX FIX FOR TRANSFORM + + if (pixmap->x <= x && x < pixmap->x + pixmap->width && + pixmap->y <= y && y < pixmap->y + pixmap->height) + { + switch (pixmap->format) { + case TWIN_A8: + return *p.a8 << 24; + case TWIN_RGB16: + return twin_rgb16_to_argb32 (*p.rgb16); + case TWIN_ARGB32: + return *p.argb32; + } + } + return 0; +} + +twin_bool_t +twin_pixmap_transparent (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y) +{ + return (_twin_pixmap_fetch (pixmap, x, y) >> 24) == 0; +} + +void +twin_pixmap_move (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y) +{ + twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); + pixmap->x = x; + pixmap->y = y; + twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); +} + +twin_bool_t +twin_pixmap_dispatch (twin_pixmap_t *pixmap, twin_event_t *event) +{ + if (pixmap->window) + return twin_window_dispatch (pixmap->window, event); + return TWIN_FALSE; +} + |