Bug 111152 - Support native pixel formats. Patch by

james.turner@crocodile-clips.com, minor tweaks by me.
This commit is contained in:
bbaetz%cs.mcgill.ca 2001-12-10 08:37:05 +00:00
Родитель 337129f6d3
Коммит 28adab5b9c
3 изменённых файлов: 349 добавлений и 14 удалений

Просмотреть файл

@ -43,7 +43,8 @@ struct _ArtRenderPriv {
ArtRender *
art_render_new (int x0, int y0, int x1, int y1,
art_u8 *pixels, int rowstride,
int n_chan, int depth, ArtAlphaType alpha_type,
ArtDestinationPixelFormat pixf,
ArtAlphaType alpha_type,
ArtAlphaGamma *alphagamma)
{
ArtRenderPriv *priv;
@ -51,7 +52,7 @@ art_render_new (int x0, int y0, int x1, int y1,
priv = art_new (ArtRenderPriv, 1);
result = &priv->super;
/*
if (n_chan > ART_MAX_CHAN)
{
art_warn ("art_render_new: n_chan = %d, exceeds %d max\n",
@ -64,6 +65,7 @@ art_render_new (int x0, int y0, int x1, int y1,
depth, ART_MAX_DEPTH);
return NULL;
}
*/
if (x0 >= x1)
{
art_warn ("art_render_new: x0 >= x1 (x0 = %d, x1 = %d)\n", x0, x1);
@ -75,8 +77,14 @@ art_render_new (int x0, int y0, int x1, int y1,
result->y1 = y1;
result->pixels = pixels;
result->rowstride = rowstride;
result->n_chan = n_chan;
result->depth = depth;
result->n_chan = 0;
if (pixf & ART_PF_RGB_MASK)
result->n_chan += 3;
result->depth = (pixf & ART_PF_CMP_SIZE_MASK) >> 8;
result->pixel_format = pixf;
result->alpha_type = alpha_type;
result->clear = ART_FALSE;
@ -189,9 +197,11 @@ art_render_clear_render_8 (ArtRenderCallback *self, ArtRender *render,
}
ix = 0;
for (i = 0; i < width; i++)
for (i = 0; i < width; i++) {
for (j = 0; j < n_ch; j++)
dest[ix++] = color[j];
}
}
const ArtRenderCallback art_render_clear_rgb8_obj =
@ -520,7 +530,10 @@ art_render_composite_8 (ArtRenderCallback *self, ArtRender *render,
int n_chan = render->n_chan;
ArtAlphaType alpha_type = render->alpha_type;
int n_ch = n_chan + (alpha_type != ART_ALPHA_NONE);
int dst_pixstride = n_ch;
/* extract the pixel size (in bits) and divide by 8 */
int dst_pixstride = (render->pixel_format & ART_PF_PIXEL_SIZE_MASK) >> 8;
ArtAlphaType buf_alpha = render->buf_alpha;
int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
int buf_pixstride = buf_n_ch;
@ -643,10 +656,297 @@ const ArtRenderCallback art_render_composite_8_obj =
art_render_nop_done
};
static void
art_render_composite_rgb8 (ArtRenderCallback *self,
ArtRender *render,
art_u8 *dest, int y)
{
ArtRenderMaskRun *run = render->run;
int n_run = render->n_run;
int x0 = render->x0;
int x;
int run_x0, run_x1;
art_u8 *alpha_buf = render->alpha_buf;
art_u8 *image_buf = render->image_buf;
int i, j;
art_u32 tmp;
art_u32 run_alpha;
art_u32 alpha;
int image_ix;
/* extract the pixel size (in bits) and divide by 8 */
int dst_pixstride = (render->pixel_format & ART_PF_PIXEL_SIZE_MASK) >> 3 ;
int n_chan = 3;
ArtAlphaType buf_alpha = render->buf_alpha;
int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
int buf_pixstride = buf_n_ch;
art_u8 *bufptr;
art_u32 src_alpha;
art_u32 src_mul;
art_u8 *dstptr;
art_u32 dst_alpha;
art_u32 dst_mul, dst_save_mul;
art_u32 src, dst;
/* art_u32 tmp; */
image_ix = 0;
for (i = 0; i < n_run - 1; i++)
{
run_x0 = run[i].x;
run_x1 = run[i + 1].x;
tmp = run[i].alpha;
if (tmp < 0x10000)
continue;
run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
bufptr = image_buf + (run_x0 - x0) * buf_pixstride;
dstptr = dest + (run_x0 - x0) * dst_pixstride;
if (render->pixel_format & ART_PF_SWAP_ALPHA_MASK)
dstptr++;
for (x = run_x0; x < run_x1; x++)
{
if (alpha_buf)
{
tmp = run_alpha * alpha_buf[x - x0] + 0x80;
/* range 0x80 .. 0xff0080 */
alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
}
else
alpha = run_alpha;
/* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
/* convert (src pixel * alpha) to premul alpha form,
store in src as 0..0xffff range */
if (buf_alpha == ART_ALPHA_NONE)
{
src_alpha = alpha;
src_mul = src_alpha;
}
else
{
tmp = alpha * bufptr[n_chan] + 0x80;
/* range 0x80 .. 0xff0080 */
src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
if (buf_alpha == ART_ALPHA_SEPARATE)
src_mul = src_alpha;
else /* buf_alpha == (ART_ALPHA_PREMUL) */
src_mul = alpha;
}
/* src_alpha is the (alpha of the source pixel * alpha),
range 0..0x10000 */
src_mul *= 0x101;
/* if (alpha_type == ART_ALPHA_NONE) */
dst_alpha = 0x10000;
dst_mul = dst_alpha;
dst_mul *= 0x101;
dst_save_mul = 0xff;
/* unrolling damage */
src = (bufptr[0] * src_mul + 0x8000) >> 16;
dst = (dstptr[0] * dst_mul + 0x8000) >> 16;
tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
tmp &= 0x0000FFFF;
dstptr[0] = (tmp * dst_save_mul + 0x8000) >> 16;
src = (bufptr[1] * src_mul + 0x8000) >> 16;
dst = (dstptr[1] * dst_mul + 0x8000) >> 16;
tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
tmp &= 0x0000FFFF;
dstptr[1] = (tmp * dst_save_mul + 0x8000) >> 16;
src = (bufptr[2] * src_mul + 0x8000) >> 16;
dst = (dstptr[2] * dst_mul + 0x8000) >> 16;
tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
tmp &= 0x0000FFFF;
dstptr[2] = (tmp * dst_save_mul + 0x8000) >> 16;
/* end of unrolled loop */
bufptr += buf_pixstride;
dstptr += dst_pixstride;
}
}
}
const ArtRenderCallback art_render_composite_rgb8_obj =
{
art_render_composite_rgb8,
art_render_nop_done
};
static void
art_render_composite_rgb5 (ArtRenderCallback *self,
ArtRender *render,
art_u8 *dest, int y)
{
ArtRenderMaskRun *run = render->run;
int n_run = render->n_run;
int x0 = render->x0;
int x;
int run_x0, run_x1;
art_u8 *alpha_buf = render->alpha_buf;
art_u8 *image_buf = render->image_buf;
int i, j;
art_u32 tmp;
art_u32 run_alpha;
art_u32 alpha;
int image_ix;
int n_chan = 3;
ArtAlphaType buf_alpha = render->buf_alpha;
int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
int buf_pixstride = buf_n_ch;
art_u8 *bufptr;
art_u32 src_alpha;
art_u32 src_mul;
art_u16 *dstptr;
art_u32 dst_alpha;
art_u32 dst_mul, dst_save_mul;
art_u32 src, dst;
art_u16 dstval,
result;
int
redShift = 7,
redMask = 0x7C00, /* bits 14 - 10 */
greenShift = 2,
greenMask = 0x03E0, /* bits 5 - 9 */
blueMask = 0x001F; /* lowest 5 bits [0 - 4] */
if (render->pixel_format & ART_PF_GREEN_6_MASK) {
redMask <<= 1; /* Red pushed left 1 */
++redShift;
greenMask += (1<<10); /* Extra bit for green */
++greenShift;
}
/* art_u32 tmp; */
image_ix = 0;
for (i = 0; i < n_run - 1; i++)
{
run_x0 = run[i].x;
run_x1 = run[i + 1].x;
tmp = run[i].alpha;
if (tmp < 0x10000)
continue;
run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
bufptr = image_buf + (run_x0 - x0) * buf_pixstride;
dstptr = ((art_u16*)dest) + (run_x0 - x0);
if (render->pixel_format & ART_PF_SWAP_ALPHA_MASK)
dstptr++;
for (x = run_x0; x < run_x1; x++)
{
if (alpha_buf)
{
tmp = run_alpha * alpha_buf[x - x0] + 0x80;
/* range 0x80 .. 0xff0080 */
alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
}
else
alpha = run_alpha;
/* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
/* convert (src pixel * alpha) to premul alpha form,
store in src as 0..0xffff range */
if (buf_alpha == ART_ALPHA_NONE)
{
src_alpha = alpha;
src_mul = src_alpha;
}
else
{
tmp = alpha * bufptr[n_chan] + 0x80;
/* range 0x80 .. 0xff0080 */
src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
if (buf_alpha == ART_ALPHA_SEPARATE)
src_mul = src_alpha;
else /* buf_alpha == (ART_ALPHA_PREMUL) */
src_mul = alpha;
}
/* src_alpha is the (alpha of the source pixel * alpha),
range 0..0x10000 */
src_mul *= 0x101;
/* if (alpha_type == ART_ALPHA_NONE) */
dst_alpha = 0x10000;
dst_mul = dst_alpha;
dst_mul *= 0x101;
dst_save_mul = 0xff;
/* unrolling damage */
dstval = *dstptr;
src = (bufptr[0] * src_mul + 0x8000) >> 16;
dst = ( ( (dstval & redMask) >> redShift ) * dst_mul + 0x8000) >> 16;
tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
tmp &= 0x0000FFFF;
result = (((tmp * dst_save_mul + 0x8000) >> 16) << redShift) & redMask;
src = (bufptr[1] * src_mul + 0x8000) >> 16;
dst = ( ((dstval & greenMask) >> greenShift) * dst_mul + 0x8000) >> 16;
tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
tmp &= 0x0000FFFF;
result |= (((tmp * dst_save_mul + 0x8000) >> 16) << greenShift) & greenMask;
src = (bufptr[2] * src_mul + 0x8000) >> 16;
dst = (((dstval & blueMask) << 3) * dst_mul + 0x8000) >> 16;
tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
tmp &= 0x0000FFFF;
result |= (((tmp * dst_save_mul + 0x8000) >> 16) >> 3) & blueMask;
*dstptr++ = result;
/* end of unrolled loop */
bufptr += buf_pixstride;
}
}
}
const ArtRenderCallback art_render_composite_rgb5_obj =
{
art_render_composite_rgb5,
art_render_nop_done
};
/* todo: inline */
static ArtRenderCallback *
art_render_choose_compositing_callback (ArtRender *render)
{
if (render->pixel_format & ART_PF_RGB_MASK) {
if (render->depth == 8 && render->buf_depth == 8)
return (ArtRenderCallback *)&art_render_composite_rgb8_obj;
if (render->depth == 5 && render->buf_depth == 8)
return (ArtRenderCallback *)&art_render_composite_rgb5_obj;
art_die("We are scrwed.");
} else
if (render->depth == 8 && render->buf_depth == 8)
return (ArtRenderCallback *)&art_render_composite_8_obj;
return (ArtRenderCallback *)&art_render_composite_obj;
@ -1079,7 +1379,7 @@ art_render_image_solid_negotiate (ArtImageSource *self, ArtRender *render,
render_cbk = NULL;
if (render->depth == 8 && render->n_chan == 3 &&
if (render->depth <= 8 && render->n_chan == 3 &&
render->alpha_type == ART_ALPHA_NONE)
{
if (render->clear)
@ -1091,7 +1391,7 @@ art_render_image_solid_negotiate (ArtImageSource *self, ArtRender *render,
}
if (render_cbk == NULL)
{
if (render->depth == 8)
if (render->depth <= 8)
{
render_cbk = art_render_image_solid_rgb8;
*p_buf_depth = 8;

Просмотреть файл

@ -73,6 +73,38 @@ typedef enum {
ART_IMAGE_SOURCE_CAN_COMPOSITE = 2
} ArtImageSourceFlags;
/* added by James Turner - note the hevay GL influence here :-) */
#define ART_PF_PIXEL_SIZE_MASK 0xFF /* bits 0 -> 7, pizel size in bits */
#define ART_PF_CMP_SIZE_MASK 0xFF00 /* bits 8 -> 15, component size in bits */
#define ART_CMP_8_BIT 8 << 8
#define ART_CMP_5_BIT 5 << 8
#define ART_CMP_16_BIT 16 << 8
#define ART_PF_RGB_MASK 1 << 16
#define ART_PF_ALPHA_MASK 1 << 17
#define ART_PF_INDEXED_MASK 1 << 18
/* alpha is before the first color component (MSB on big-endian) */
#define ART_PF_SWAP_ALPHA_MASK 1 << 19
#define ART_PF_GREEN_6_MASK 1 << 20
typedef enum {
ART_PF_RGB8 = ART_PF_RGB_MASK | ART_CMP_8_BIT | 24, /* current default */
ART_PF_RGB16 = ART_PF_RGB_MASK | ART_CMP_16_BIT | 48,
ART_PF_RGBA8 = ART_PF_RGB_MASK | ART_PF_ALPHA_MASK | ART_CMP_8_BIT | 32,
/* suprisingly common - needed for mac */
ART_PF_ARGB8 = ART_PF_RGB_MASK | ART_PF_ALPHA_MASK | ART_PF_SWAP_ALPHA_MASK | ART_CMP_8_BIT | 32,
ART_PF_555 = ART_PF_RGB_MASK | ART_CMP_5_BIT | 16,
ART_PF_565 = ART_PF_RGB_MASK | ART_PF_GREEN_6_MASK | ART_CMP_5_BIT | 16,
/* highly questionable .... */
ART_PF_INDEXED8 = ART_PF_INDEXED_MASK | 8
} ArtDestinationPixelFormat;
/* end of te pixel format damage */
struct _ArtRenderMaskRun {
int x;
int alpha;
@ -109,6 +141,7 @@ struct _ArtRender {
int n_chan;
int depth;
ArtAlphaType alpha_type;
ArtDestinationPixelFormat pixel_format;
art_boolean clear;
ArtPixMaxDepth clear_color[ART_MAX_CHAN + 1];
@ -140,7 +173,8 @@ struct _ArtRender {
ArtRender *
art_render_new (int x0, int y0, int x1, int y1,
art_u8 *pixels, int rowstride,
int n_chan, int depth, ArtAlphaType alpha_type,
ArtDestinationPixelFormat pixf,
ArtAlphaType alpha_type,
ArtAlphaGamma *alphagamma);
void

Просмотреть файл

@ -432,8 +432,8 @@ test_render_gradient (art_u8 *buf)
vpath = randstar (50);
svp = art_svp_from_vpath (vpath);
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
NULL);
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, ART_PF_RGB8,
ART_ALPHA_NONE, NULL);
art_render_svp (render, svp);
art_render_gradient_linear (render, &gradient, ART_FILTER_NEAREST);
art_render_invoke (render);
@ -468,8 +468,8 @@ test_render_rad_gradient (art_u8 *buf)
vpath = randstar (50);
svp = art_svp_from_vpath (vpath);
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
NULL);
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, ART_PF_RGB8,
ART_ALPHA_NONE, NULL);
art_render_svp (render, svp);
art_render_gradient_radial (render, &gradient, ART_FILTER_NEAREST);
art_render_invoke (render);
@ -494,7 +494,8 @@ test_gradient (void)
{
#define USE_RENDER
#ifdef USE_RENDER
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, ART_PF_RGB8,
ART_ALPHA_NONE,
NULL);
art_render_clear_rgb (render, 0xfff0c0);
art_render_svp (render, svp);