/* Copyright 1994, 1995 by Abacus Research and * Development, Inc. All rights reserved. */ #if !defined (OMIT_RCSID_STRINGS) char ROMlib_rcsid_qScale[] = "$Id: qScale.c 87 2005-05-25 01:57:33Z ctm $"; #endif #include "rsys/common.h" #include "QuickDraw.h" #include "CQuickDraw.h" #include "rsys/cquick.h" /* This routine scales old_bitmap and stores the result in dst_bitmap. * The only field of dst_bitmap that needs to be valid on entry is * baseAddr, which should point to enough information to hold the * resulting scaled bitmap, with rowBytes evenly divisble by 4. * dst_bitmap's bounds will be filled in such that "new_rect" will refer * to the newly scaled bits in that coordinate system. */ void scale_blt_bitmap (const blt_bitmap_t *src_bitmap, blt_bitmap_t *dst_bitmap, const Rect *old_rect, const Rect *new_rect, int log2_bits_per_pixel) { long old_width, new_width, old_height, new_height; long y, dx, dy, left_x, src_rowbytes, dst_rowbytes, dst_byte_width, old_v; long rows_left; const uint8 *src_base; uint8 *dst_row_base; /* Fetch the sizes of the two bitmaps. */ old_width = RECT_WIDTH (old_rect); new_width = RECT_WIDTH (new_rect); old_height = RECT_HEIGHT (old_rect); new_height = RECT_HEIGHT (new_rect); /* If the old bitmap was empty, just create a new, empty bitmap. We * do this to avoid dividing by zero. */ if (new_width == 0 || new_height == 0) { dst_bitmap->bounds.left = dst_bitmap->bounds.right = dst_bitmap->bounds.top = dst_bitmap->bounds.bottom = CWC (0); /*->*/return; } /* Compute the scale ratio as a fixed-point number. */ dx = (old_width << 16) / new_width; dy = (old_height << 16) / new_height; /* Compute some parameters for the main loop. */ dst_byte_width = ((new_width << log2_bits_per_pixel) + 7) / 8; dst_rowbytes = (dst_byte_width + 3) & ~3; /* Divisible by 4. */ src_rowbytes = BITMAP_ROWBYTES (src_bitmap); dst_row_base = (uint8 *) MR (dst_bitmap->baseAddr); src_base = (uint8 *) (MR (src_bitmap->baseAddr) + ((CW (old_rect->top) - CW (src_bitmap->bounds.top)) * src_rowbytes)); left_x = (CW (old_rect->left) - CW (src_bitmap->bounds.left)) << 16; old_v = -1; /* This macro expresses the main horizontal scaling loop. The bits * for each byte in the destination bitmap are grabbed and ORed together, * and then written out. */ #define SCALE_LOOP(x_count, scale_code) \ for (rows_left = new_height, y = 0; rows_left > 0; y += dy, rows_left--) \ { \ long v = y >> 16; \ if (v == old_v) \ { \ memcpy (dst_row_base, dst_row_base - dst_rowbytes, dst_byte_width); \ } \ else \ { \ long x, h; \ const unsigned char *src_row_base; \ \ /* Loop across this row. */ \ src_row_base = &src_base[src_rowbytes * v]; \ for (h = 0, x = left_x; h < (x_count); h++) \ { \ scale_code; \ } \ \ old_v = v; \ } \ dst_row_base += dst_rowbytes; \ } /* This helper macro grabs the bits corresponding to the x / 65536th pixel * from src_row_base on the current line, assuming the specified number of * bits per pixel. FIXME: this code can read beyond the end of src_bitmap's * memory when collecting unneeded boundary pixels. */ #undef BITS #define BITS(log2_bpp) \ ((src_row_base[x >> (19 - (log2_bpp))] /* This is the containing byte. */\ >> (((~(x >> 16)) & (7 >> (log2_bpp))) /* Pixel # within that byte. */\ << (log2_bpp))) /* Scale by pixel size. */\ & ((1 << (1 << (log2_bpp))) - 1)) /* Mask out all but wanted bits. */ /* #warning "Can look too far into memory for the boundary pixels" */ switch (log2_bits_per_pixel) { case 0: /* 1 bpp */ SCALE_LOOP (dst_byte_width, { unsigned char new; new = BITS (0) << 7; x += dx; new |= BITS (0) << 6; x += dx; new |= BITS (0) << 5; x += dx; new |= BITS (0) << 4; x += dx; new |= BITS (0) << 3; x += dx; new |= BITS (0) << 2; x += dx; new |= BITS (0) << 1; x += dx; new |= BITS (0); x += dx; dst_row_base[h] = new; }); break; case 1: /* 2 bpp */ SCALE_LOOP (dst_byte_width, { unsigned char new; new = BITS (1) << 6; x += dx; new |= BITS (1) << 4; x += dx; new |= BITS (1) << 2; x += dx; new |= BITS (1); x += dx; dst_row_base[h] = new; }); break; case 2: /* 4 bpp */ SCALE_LOOP (dst_byte_width, { unsigned char new; new = BITS (2) << 4; x += dx; new |= BITS (2); x += dx; dst_row_base[h] = new; }); break; case 3: /* 8 bpp */ SCALE_LOOP (dst_byte_width, { dst_row_base[h] = BITS (3); x += dx; }); break; case 4: SCALE_LOOP (new_width, { ((uint16 *) dst_row_base)[h] = ((uint16 *) src_row_base)[x >> 16]; x += dx; }); break; case 5: SCALE_LOOP (new_width, { ((uint32 *) dst_row_base)[h] = ((uint32 *) src_row_base)[x >> 16]; x += dx; }); break; default: gui_fatal ("invalid target depth %d", (1 << log2_bits_per_pixel)); } BITMAP_SET_ROWBYTES_X (dst_bitmap, CW (dst_rowbytes)); dst_bitmap->bounds = *new_rect; }