Files
freetype/test/blitter.c
2023-08-27 18:03:45 +02:00

493 lines
13 KiB
C

/****************************************************************************/
/* */
/* The FreeType project -- a free and portable quality TrueType renderer. */
/* */
/* Copyright 1996-1999 by */
/* D. Turner, R.Wilhelm, and W. Lemberg */
/* */
/* blitter.c: Support for blitting of bitmaps with various depth. */
/* */
/****************************************************************************/
#include "blitter.h"
typedef struct TBlitter_
{
int width; /* width in pixels of the written area */
int height; /* height in pixels of the written area */
int xread; /* x position of start point in read area */
int yread; /* y position of start point in read area */
int xwrite; /* x position of start point in write area */
int ywrite; /* y position of start point in write area */
int right_clip; /* amount of right clip */
char* read; /* top left corner of source map */
char* write; /* top left corner of target map */
int read_line; /* byte increment to go down one row in read area */
int write_line; /* byte increment to go down one row in write area */
TT_Raster_Map source;
TT_Raster_Map target;
int source_depth;
int target_depth;
} TBlitter;
static
int compute_clips( TBlitter* blit,
int x_offset,
int y_offset )
{
int xmin, ymin, xmax, ymax, width, height, target_width;
/* perform clipping and setup variables */
width = blit->source.width;
height = blit->source.rows;
switch ( blit->source_depth )
{
case 1:
width = (width + 7) & -8;
break;
case 4:
width = (width + 1) & -2;
break;
}
xmin = x_offset;
ymin = y_offset;
xmax = xmin + width-1;
ymax = ymin + height-1;
/* clip if necessary */
if ( width == 0 || height == 0 ||
xmax < 0 || xmin >= blit->target.width ||
ymax < 0 || ymin >= blit->target.rows )
return 1;
/* set up clipping and cursors */
blit->yread = 0;
if ( ymin < 0 )
{
blit->yread -= ymin;
height += ymin;
blit->ywrite = 0;
}
else
blit->ywrite = ymin;
if ( ymax >= blit->target.rows )
height -= ymax - blit->target.rows + 1;
blit->xread = 0;
if ( xmin < 0 )
{
blit->xread -= xmin;
width += xmin;
blit->xwrite = 0;
}
else
blit->xwrite = xmin;
target_width = blit->target.width;
switch ( blit->target_depth )
{
case 1:
target_width = (target_width + 7) & -8;
break;
case 4:
target_width = (target_width + 1) & -2;
break;
}
blit->right_clip = xmax - target_width + 1;
if ( blit->right_clip > 0 )
width -= blit->right_clip;
else
blit->right_clip = 0;
blit->width = width;
blit->height = height;
/* set read and write to the top-left corner of the the read */
/* and write area before clipping. */
blit->read = (char*)blit->source.bitmap;
blit->write = (char*)blit->target.bitmap;
if ( blit->source.flow == TT_Flow_Up )
{
blit->read_line = -blit->source.cols;
blit->read += (blit->source.rows-1) * blit->source.cols;
}
else
blit->read_line = blit->source.cols;
if ( blit->target.flow == TT_Flow_Up )
{
blit->write_line = -blit->target.cols;
blit->write += (blit->target.rows-1) * blit->target.cols;
}
else
blit->write_line = blit->target.cols;
/* now go to the start line. Note that we do not move the */
/* x position yet, as this is dependent on the pixel format */
blit->read += blit->yread * blit->read_line;
blit->write += blit->ywrite * blit->write_line;
return 0;
}
/**************************************************************************/
/* */
/* <Function> blit_bitmap_to_bitmap */
/* */
/**************************************************************************/
static
void blit_bitmap_to_bitmap( TBlitter* blit )
{
int shift, left_clip, x, y;
unsigned char* read;
unsigned char* write;
left_clip = ( blit->xread > 0 );
shift = ( blit->xwrite - blit->xread ) & 7;
read = (unsigned char*)blit->read + (blit->xread >> 3);
write = (unsigned char*)blit->write + (blit->xwrite >> 3);
if ( shift == 0 )
{
y = blit->height;
do
{
unsigned char* _read = read;
unsigned char* _write = write;
x = blit->width;
do
{
*_write++ |= *_read++;
x -= 8;
} while ( x > 0 );
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
else
{
int first, last, count;
first = blit->xwrite >> 3;
last = (blit->xwrite + blit->width-1) >> 3;
count = last - first;
if ( blit->right_clip )
count++;
y = blit->height;
do
{
unsigned char* _read = read;
unsigned char* _write = write;
unsigned char old;
int shift2 = (8-shift);
if ( left_clip )
old = (*_read++) << shift2;
else
old = 0;
x = count;
while ( x > 0 )
{
unsigned char val;
val = *_read++;
*_write++ |= ( (val >> shift) | old );
old = val << shift2;
x--;
}
if ( !blit->right_clip )
*_write |= old;
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
}
/**************************************************************************/
/* */
/* <Function> blit_bitmap_to_pixmap8 */
/* */
/**************************************************************************/
static
void blit_bitmap_to_pixmap8( TBlitter* blit,
unsigned char color )
{
int x, y;
unsigned int left_mask;
unsigned char* read;
unsigned char* write;
read = (unsigned char*)blit->read + (blit->xread >> 3);
write = (unsigned char*)blit->write + blit->xwrite;
left_mask = 0x80 >> (blit->xread & 7);
y = blit->height;
do
{
unsigned char* _read = read;
unsigned char* _write = write;
unsigned int mask = left_mask;
unsigned int val = 0;
x = blit->width;
do
{
if ( mask == 0x80 )
val = *_read++;
if ( val & mask )
*_write = (unsigned char)color;
mask >>= 1;
if ( mask == 0 )
mask = 0x80;
_write++;
x--;
} while ( x > 0 );
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
/**************************************************************************/
/* */
/* <Function> blit_bitmap_to_pixmap4 */
/* */
/**************************************************************************/
static
void blit_bitmap_to_pixmap4( TBlitter* blit,
unsigned char color )
{
int x, y, phase;
unsigned int left_mask;
unsigned char* read;
unsigned char* write;
color = color & 15;
read = (unsigned char*)blit->read + (blit->xread >> 3);
write = (unsigned char*)blit->write + (blit->xwrite >> 1);
/* now begin blit */
left_mask = 0x80 >> (blit->xread & 7);
phase = blit->xwrite & 1;
y = blit->height;
do
{
unsigned char* _read = read;
unsigned char* _write = write;
unsigned int mask = left_mask;
int _phase = phase;
unsigned int val = 0;
x = blit->width;
do
{
if ( mask == 0x80 )
val = *_read++;
if ( val & mask )
{
if ( _phase )
*_write = (*_write & 0xF0) | color;
else
*_write = (*_write & 0x0F) | (color << 4);
}
mask >>= 1;
if ( mask == 0 )
mask = 0x80;
_write += _phase;
_phase ^= 1;
x--;
} while ( x > 0 );
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
/**************************************************************************/
/* */
/* <Function> blit_bitmap_to_pixmap16 */
/* */
/**************************************************************************/
static
void blit_bitmap_to_pixmap16( TBlitter* blit,
unsigned short color )
{
int x, y;
unsigned int left_mask;
unsigned char* read;
unsigned short* write;
read = (unsigned char*)blit->read + (blit->xread >> 3);
write = (unsigned short*)(blit->write + blit->xwrite*2);
left_mask = 0x80 >> (blit->xread & 7);
y = blit->height;
do
{
unsigned char* _read = read;
unsigned short* _write = write;
unsigned int mask = left_mask;
unsigned int val = 0;
x = blit->width;
do
{
if ( mask == 0x80 )
val = *_read++;
if ( val & mask )
*_write = color;
mask >>= 1;
if ( mask == 0 )
mask = 0x80;
_write++;
x--;
} while ( x > 0 );
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
/* <Function> */
/* Blit_Bitmap */
/* */
/* <Description> */
/* blit a source bitmap to a target bitmap or pixmap */
/* */
/* <Input> */
/* target :: target bitmap or pixmap */
/* source :: source bitmap (depth must be 1) */
/* target_depth :: pixel bit depth of target map */
/* x_offset :: horizontal offset of source in target */
/* y_offset :: vertical offset of source in target */
/* color :: color to use when blitting to color pixmap */
/* */
/* <Return> */
/* error code. 0 means success */
/* */
/* <Note> */
/* an error occurs when the target bit depth isn't supported, or */
/* if the source's bit depth isn't 1. */
/* */
/* the offsets are relative to the top-left corner of the target */
/* map. Positive y are downwards. */
/* */
extern
int Blit_Bitmap( TT_Raster_Map* target,
TT_Raster_Map* source,
int target_depth,
int x_offset,
int y_offset,
int color )
{
TBlitter blit;
if ( !target || !source )
return -1;
blit.source = *source;
blit.target = *target;
blit.source_depth = 1;
blit.target_depth = target_depth;
/* set up blitter and compute clipping. Return immediately if needed */
if ( compute_clips( &blit, x_offset, y_offset ) )
return 0;
/* now perform the blit */
switch ( target_depth )
{
case 1:
blit_bitmap_to_bitmap( &blit );
break;
case 4:
blit_bitmap_to_pixmap4( &blit, (unsigned char)color );
break;
case 8:
blit_bitmap_to_pixmap8( &blit, (unsigned char)color );
break;
case 16:
blit_bitmap_to_pixmap16( &blit, (unsigned short)color );
break;
default:
return -2;
}
return 0;
}
/* End */