mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-27 21:19:18 +00:00
260 lines
6.6 KiB
C
260 lines
6.6 KiB
C
/*
|
|
* art_rgba.c: Functions for manipulating RGBA pixel data.
|
|
*
|
|
* Libart_LGPL - library of basic graphic primitives
|
|
* Copyright (C) 2000 Raph Levien
|
|
*
|
|
* 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 this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "art_misc.h"
|
|
#include "art_rgba.h"
|
|
|
|
#define ART_OPTIMIZE_SPACE
|
|
|
|
#ifndef ART_OPTIMIZE_SPACE
|
|
#include "art_rgba_table.c"
|
|
#endif
|
|
|
|
/**
|
|
* art_rgba_rgba_composite: Composite RGBA image over RGBA buffer.
|
|
* @dst: Destination RGBA buffer.
|
|
* @src: Source RGBA buffer.
|
|
* @n: Number of RGBA pixels to composite.
|
|
*
|
|
* Composites the RGBA pixels in @dst over the @src buffer.
|
|
**/
|
|
void
|
|
art_rgba_rgba_composite (art_u8 *dst, const art_u8 *src, int n)
|
|
{
|
|
int i;
|
|
#ifdef WORDS_BIGENDIAN
|
|
art_u32 src_rgba, dst_rgba;
|
|
#else
|
|
art_u32 src_abgr, dst_abgr;
|
|
#endif
|
|
art_u8 src_alpha, dst_alpha;
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
src_rgba = ((art_u32 *)src)[i];
|
|
src_alpha = src_rgba & 0xff;
|
|
#else
|
|
src_abgr = ((art_u32 *)src)[i];
|
|
src_alpha = (src_abgr >> 24) & 0xff;
|
|
#endif
|
|
if (src_alpha)
|
|
{
|
|
if (src_alpha == 0xff ||
|
|
(
|
|
#ifdef WORDS_BIGENDIAN
|
|
dst_rgba = ((art_u32 *)dst)[i],
|
|
dst_alpha = dst_rgba & 0xff,
|
|
#else
|
|
dst_abgr = ((art_u32 *)dst)[i],
|
|
dst_alpha = (dst_abgr >> 24),
|
|
#endif
|
|
dst_alpha == 0))
|
|
#ifdef WORDS_BIGENDIAN
|
|
((art_u32 *)dst)[i] = src_rgba;
|
|
#else
|
|
((art_u32 *)dst)[i] = src_abgr;
|
|
#endif
|
|
else
|
|
{
|
|
int r, g, b, a;
|
|
int src_r, src_g, src_b;
|
|
int dst_r, dst_g, dst_b;
|
|
int tmp;
|
|
int c;
|
|
|
|
#ifdef ART_OPTIMIZE_SPACE
|
|
tmp = (255 - src_alpha) * (255 - dst_alpha) + 0x80;
|
|
a = 255 - ((tmp + (tmp >> 8)) >> 8);
|
|
c = ((src_alpha << 16) + (a >> 1)) / a;
|
|
#else
|
|
tmp = art_rgba_composite_table[(src_alpha << 8) + dst_alpha];
|
|
c = tmp & 0x1ffff;
|
|
a = tmp >> 24;
|
|
#endif
|
|
#ifdef WORDS_BIGENDIAN
|
|
src_r = (src_rgba >> 24) & 0xff;
|
|
src_g = (src_rgba >> 16) & 0xff;
|
|
src_b = (src_rgba >> 8) & 0xff;
|
|
dst_r = (dst_rgba >> 24) & 0xff;
|
|
dst_g = (dst_rgba >> 16) & 0xff;
|
|
dst_b = (dst_rgba >> 8) & 0xff;
|
|
#else
|
|
src_r = src_abgr & 0xff;
|
|
src_g = (src_abgr >> 8) & 0xff;
|
|
src_b = (src_abgr >> 16) & 0xff;
|
|
dst_r = dst_abgr & 0xff;
|
|
dst_g = (dst_abgr >> 8) & 0xff;
|
|
dst_b = (dst_abgr >> 16) & 0xff;
|
|
#endif
|
|
r = dst_r + (((src_r - dst_r) * c + 0x8000) >> 16);
|
|
g = dst_g + (((src_g - dst_g) * c + 0x8000) >> 16);
|
|
b = dst_b + (((src_b - dst_b) * c + 0x8000) >> 16);
|
|
#ifdef WORDS_BIGENDIAN
|
|
((art_u32 *)dst)[i] = (r << 24) | (g << 16) | (b << 8) | a;
|
|
#else
|
|
((art_u32 *)dst)[i] = (a << 24) | (b << 16) | (g << 8) | r;
|
|
#endif
|
|
}
|
|
}
|
|
#if 0
|
|
/* it's not clear to me this optimization really wins */
|
|
else
|
|
{
|
|
/* skip over run of transparent pixels */
|
|
for (; i < n - 1; i++)
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
src_rgba = ((art_u32 *)src)[i + 1];
|
|
if (src_rgba & 0xff)
|
|
break;
|
|
#else
|
|
src_abgr = ((art_u32 *)src)[i + 1];
|
|
if (src_abgr & 0xff000000)
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/**
|
|
* art_rgba_fill_run: fill an RGBA buffer a solid RGB color.
|
|
* @buf: Buffer to fill.
|
|
* @r: Red, range 0..255.
|
|
* @g: Green, range 0..255.
|
|
* @b: Blue, range 0..255.
|
|
* @n: Number of RGB triples to fill.
|
|
*
|
|
* Fills a buffer with @n copies of the (@r, @g, @b) triple, solid
|
|
* alpha. Thus, locations @buf (inclusive) through @buf + 4 * @n
|
|
* (exclusive) are written.
|
|
**/
|
|
void
|
|
art_rgba_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n)
|
|
{
|
|
int i;
|
|
#ifdef WORDS_BIGENDIAN
|
|
art_u32 src_rgba;
|
|
#else
|
|
art_u32 src_abgr;
|
|
#endif
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
src_rgba = (r << 24) | (g << 16) | (b << 8) | 255;
|
|
#else
|
|
src_abgr = (255 << 24) | (b << 16) | (g << 8) | r;
|
|
#endif
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
((art_u32 *)buf)[i] = src_rgba;
|
|
#else
|
|
((art_u32 *)buf)[i] = src_abgr;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/**
|
|
* art_rgba_run_alpha: Render semitransparent color over RGBA buffer.
|
|
* @buf: Buffer for rendering.
|
|
* @r: Red, range 0..255.
|
|
* @g: Green, range 0..255.
|
|
* @b: Blue, range 0..255.
|
|
* @alpha: Alpha, range 0..255.
|
|
* @n: Number of RGB triples to render.
|
|
*
|
|
* Renders a sequential run of solid (@r, @g, @b) color over @buf with
|
|
* opacity @alpha. Note that the range of @alpha is 0..255, in contrast
|
|
* to art_rgb_run_alpha, which has a range of 0..256.
|
|
**/
|
|
void
|
|
art_rgba_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
|
|
{
|
|
int i;
|
|
#ifdef WORDS_BIGENDIAN
|
|
art_u32 src_rgba, dst_rgba;
|
|
#else
|
|
art_u32 src_abgr, dst_abgr;
|
|
#endif
|
|
art_u8 dst_alpha;
|
|
int a;
|
|
int dst_r, dst_g, dst_b;
|
|
int tmp;
|
|
int c;
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
src_rgba = (r << 24) | (g << 16) | (b << 8) | alpha;
|
|
#else
|
|
src_abgr = (alpha << 24) | (b << 16) | (g << 8) | r;
|
|
#endif
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
dst_rgba = ((art_u32 *)buf)[i];
|
|
dst_alpha = dst_rgba & 0xff;
|
|
#else
|
|
dst_abgr = ((art_u32 *)buf)[i];
|
|
dst_alpha = (dst_abgr >> 24) & 0xff;
|
|
#endif
|
|
if (dst_alpha)
|
|
{
|
|
#ifdef ART_OPTIMIZE_SPACE
|
|
tmp = (255 - alpha) * (255 - dst_alpha) + 0x80;
|
|
a = 255 - ((tmp + (tmp >> 8)) >> 8);
|
|
c = ((alpha << 16) + (a >> 1)) / a;
|
|
#else
|
|
tmp = art_rgba_composite_table[(alpha << 8) + dst_alpha];
|
|
c = tmp & 0x1ffff;
|
|
a = tmp >> 24;
|
|
#endif
|
|
#ifdef WORDS_BIGENDIAN
|
|
dst_r = (dst_rgba >> 24) & 0xff;
|
|
dst_g = (dst_rgba >> 16) & 0xff;
|
|
dst_b = (dst_rgba >> 8) & 0xff;
|
|
#else
|
|
dst_r = dst_abgr & 0xff;
|
|
dst_g = (dst_abgr >> 8) & 0xff;
|
|
dst_b = (dst_abgr >> 16) & 0xff;
|
|
#endif
|
|
dst_r += (((r - dst_r) * c + 0x8000) >> 16);
|
|
dst_g += (((g - dst_g) * c + 0x8000) >> 16);
|
|
dst_b += (((b - dst_b) * c + 0x8000) >> 16);
|
|
#ifdef WORDS_BIGENDIAN
|
|
((art_u32 *)buf)[i] = (dst_r << 24) | (dst_g << 16) | (dst_b << 8) | a;
|
|
#else
|
|
((art_u32 *)buf)[i] = (a << 24) | (dst_b << 16) | (dst_g << 8) | dst_r;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
((art_u32 *)buf)[i] = src_rgba;
|
|
#else
|
|
((art_u32 *)buf)[i] = src_abgr;
|
|
#endif
|
|
}
|
|
}
|
|
}
|