executor/src/qScale.c

193 lines
5.5 KiB
C

/* 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;
}