Implemented DISSOLVE_MODE the way it should have always been. Fixes bug

2003-06-02  Michael Natterer  <mitch@gimp.org>

	Implemented DISSOLVE_MODE the way it should have always been.
	Fixes bug #107402.

	* app/paint-funcs-generic.h (struct apply_layer_mode_struct): added
	"guchar *mask" so it can be used by the layer mode.

	(dissolve_pixels): take an additional "mask" parameter and
	dissolve the pixels according to the *combined* opacity of the
	pixel's alpha, the opacity and the mask. Removed a wrong comment
	about why we call g_rand_int() x times before we start to use its
	values.

	(layer_dissolve_mode): pass the mask to dissolve_pixels(). No need
	to call add_alpha_pixels() since we overwrite the dest buffer
	entirely in disolve_pixels().

	* app/paint-funcs.c (initial_sub_region, combine_sub_region):
	allocate the buffer large enough for DISSOLVE (which always needs
	an alpha channel). Pass the mask to the layer mode functions.
	Discard opacity and mask after applying DISSOLVE since it
	"consumes" all transparency.
This commit is contained in:
Michael Natterer
2003-06-02 14:21:01 +00:00
committed by Michael Natterer
parent f155bb6b4b
commit 1871d9ccef
3 changed files with 119 additions and 43 deletions

View File

@ -1,3 +1,27 @@
2003-06-02 Michael Natterer <mitch@gimp.org>
Implemented DISSOLVE_MODE the way it should have always been.
Fixes bug #107402.
* app/paint-funcs-generic.h (struct apply_layer_mode_struct): added
"guchar *mask" so it can be used by the layer mode.
(dissolve_pixels): take an additional "mask" parameter and
dissolve the pixels according to the *combined* opacity of the
pixel's alpha, the opacity and the mask. Removed a wrong comment
about why we call g_rand_int() x times before we start to use its
values.
(layer_dissolve_mode): pass the mask to dissolve_pixels(). No need
to call add_alpha_pixels() since we overwrite the dest buffer
entirely in disolve_pixels().
* app/paint-funcs.c (initial_sub_region, combine_sub_region):
allocate the buffer large enough for DISSOLVE (which always needs
an alpha channel). Pass the mask to the layer mode functions.
Discard opacity and mask after applying DISSOLVE since it
"consumes" all transparency.
2003-06-02 Sven Neumann <sven@gimp.org> 2003-06-02 Sven Neumann <sven@gimp.org>
* plug-ins/common/grid.c: fixed swapped horizontal/vertical * plug-ins/common/grid.c: fixed swapped horizontal/vertical

View File

@ -53,9 +53,10 @@
struct apply_layer_mode_struct struct apply_layer_mode_struct
{ {
guchar bytes1 : 3; guchar bytes1 : 3;
guchar bytes2 : 3; guchar bytes2 : 3;
guchar *src1; guchar *src1;
guchar *src2; guchar *src2;
guchar *mask;
guchar **dest; guchar **dest;
gint x; gint x;
gint y; gint y;
@ -946,6 +947,7 @@ difference_pixels (const guchar *src1,
static inline void static inline void
dissolve_pixels (const guchar *src, dissolve_pixels (const guchar *src,
guchar *mask,
guchar *dest, guchar *dest,
gint x, gint x,
gint y, gint y,
@ -955,17 +957,17 @@ dissolve_pixels (const guchar *src,
gint db, gint db,
guint has_alpha) guint has_alpha)
{ {
gint alpha, b; gint alpha, b;
gint32 rand_val; gint32 rand_val;
GRand *gr; gint combined_opacity;
GRand *gr;
gr = g_rand_new_with_seed (random_table[y % RANDOM_TABLE_SIZE]); gr = g_rand_new_with_seed (random_table[y % RANDOM_TABLE_SIZE]);
/* Ignore a few random values (this probably isn't necessary /* Ignore x random values so we get a deterministic result */
* when using g_rand_*) */
for (b = 0; b < x; b ++) for (b = 0; b < x; b ++)
g_rand_int(gr); g_rand_int (gr);
alpha = db - 1; alpha = db - 1;
while (length--) while (length--)
@ -977,13 +979,27 @@ dissolve_pixels (const guchar *src,
/* dissolve if random value is > opacity */ /* dissolve if random value is > opacity */
rand_val = g_rand_int_range (gr, 0, 256); rand_val = g_rand_int_range (gr, 0, 256);
if (has_alpha) if (mask)
dest[alpha] = (rand_val > src[alpha]) ? 0 : src[alpha]; {
else if (has_alpha)
dest[alpha] = (rand_val > opacity) ? 0 : OPAQUE_OPACITY; combined_opacity = opacity * src[alpha] * *mask / (255 * 255);
else
combined_opacity = opacity * *mask / 255;
mask++;
}
else
{
if (has_alpha)
combined_opacity = opacity * src[alpha] / 255;
else
combined_opacity = opacity;
}
dest[alpha] = (rand_val > combined_opacity) ? 0 : OPAQUE_OPACITY;
dest += db;
src += sb; src += sb;
dest += db;
} }
g_rand_free (gr); g_rand_free (gr);
@ -1591,15 +1607,21 @@ static void
layer_dissolve_mode (struct apply_layer_mode_struct *alms) layer_dissolve_mode (struct apply_layer_mode_struct *alms)
{ {
const guint has_alpha1 = HAS_ALPHA (alms->bytes1); const guint has_alpha1 = HAS_ALPHA (alms->bytes1);
const guint has_alpha2 = HAS_ALPHA (alms->bytes2); const guint has_alpha2 = HAS_ALPHA (alms->bytes2);
guint dest_bytes;
/* Since dissolve requires an alpha channel... */ /* Since dissolve requires an alpha channel... */
if (!has_alpha2) if (has_alpha2)
add_alpha_pixels (alms->src2, *(alms->dest), alms->length, alms->bytes2); dest_bytes = alms->bytes2;
else
dest_bytes = alms->bytes2 + 1;
dissolve_pixels (alms->src2, alms->mask, *(alms->dest),
alms->x, alms->y,
alms->opacity, alms->length,
alms->bytes2, dest_bytes,
has_alpha2);
dissolve_pixels (alms->src2, *(alms->dest), alms->x, alms->y,
alms->opacity, alms->length, alms->bytes2,
(has_alpha2 ? alms->bytes2 : alms->bytes2 + 1), has_alpha2);
alms->combine = has_alpha1 ? COMBINE_INTEN_A_INTEN_A : COMBINE_INTEN_INTEN_A; alms->combine = has_alpha1 ? COMBINE_INTEN_A_INTEN_A : COMBINE_INTEN_INTEN_A;
} }

View File

@ -4296,6 +4296,7 @@ initial_sub_region (struct initial_regions_struct *st,
gboolean *affect; gboolean *affect;
InitialMode type; InitialMode type;
/* use src->bytes + 1 since DISSOLVE always needs a buffer with alpha */
buf = alloca (MAX (src->w * (src->bytes + 1), buf = alloca (MAX (src->w * (src->bytes + 1),
dest->w * dest->bytes)); dest->w * dest->bytes));
data = st->data; data = st->data;
@ -4306,7 +4307,7 @@ initial_sub_region (struct initial_regions_struct *st,
s = src->data; s = src->data;
d = dest->data; d = dest->data;
m = (mask) ? mask->data : NULL; m = mask ? mask->data : NULL;
for (h = 0; h < src->h; h++) for (h = 0; h < src->h; h++)
{ {
@ -4329,10 +4330,12 @@ initial_sub_region (struct initial_regions_struct *st,
case INITIAL_INTENSITY: case INITIAL_INTENSITY:
if (mode == GIMP_DISSOLVE_MODE) if (mode == GIMP_DISSOLVE_MODE)
{ {
dissolve_pixels (s, buf, src->x, src->y + h, opacity, src->w, src->bytes, dissolve_pixels (s, m, buf, src->x, src->y + h,
src->bytes + 1, 0); opacity, src->w,
initial_inten_pixels (buf, d, m, opacity, affect, src->bytes, src->bytes + 1,
src->w, src->bytes); FALSE);
initial_inten_a_pixels (buf, d, NULL, OPAQUE_OPACITY, affect,
src->w, src->bytes + 1);
} }
else else
initial_inten_pixels (s, d, m, opacity, affect, src->w, src->bytes); initial_inten_pixels (s, d, m, opacity, affect, src->w, src->bytes);
@ -4341,9 +4344,11 @@ initial_sub_region (struct initial_regions_struct *st,
case INITIAL_INTENSITY_ALPHA: case INITIAL_INTENSITY_ALPHA:
if (mode == GIMP_DISSOLVE_MODE) if (mode == GIMP_DISSOLVE_MODE)
{ {
dissolve_pixels (s, buf, src->x, src->y + h, opacity, src->w, src->bytes, dissolve_pixels (s, m, buf, src->x, src->y + h,
src->bytes, 1); opacity, src->w,
initial_inten_a_pixels (buf, d, m, opacity, affect, src->bytes, src->bytes,
TRUE);
initial_inten_a_pixels (buf, d, NULL, OPAQUE_OPACITY, affect,
src->w, src->bytes); src->w, src->bytes);
} }
else else
@ -4439,6 +4444,8 @@ combine_sub_region (struct combine_regions_struct *st,
{ {
guchar *data; guchar *data;
guint opacity; guint opacity;
guint layer_mode_opacity;
guchar *layer_mode_mask;
GimpLayerModeEffects mode; GimpLayerModeEffects mode;
gboolean *affect; gboolean *affect;
guint h; guint h;
@ -4452,9 +4459,11 @@ combine_sub_region (struct combine_regions_struct *st,
gboolean transparency_quickskip_possible; gboolean transparency_quickskip_possible;
TileRowHint hint; TileRowHint hint;
/* use src2->bytes + 1 since DISSOLVE always needs a buffer with alpha */
buf = alloca (MAX (MAX (src1->w * src1->bytes, buf = alloca (MAX (MAX (src1->w * src1->bytes,
src2->w * src2->bytes), src2->w * (src2->bytes + 1)),
dest->w * dest->bytes)); dest->w * dest->bytes));
opacity = st->opacity; opacity = st->opacity;
mode = st->mode; mode = st->mode;
affect = st->affect; affect = st->affect;
@ -4469,7 +4478,7 @@ combine_sub_region (struct combine_regions_struct *st,
s1 = src1->data; s1 = src1->data;
s2 = src2->data; s2 = src2->data;
d = dest->data; d = dest->data;
m = (mask) ? mask->data : NULL; m = mask ? mask->data : NULL;
if (transparency_quickskip_possible || opacity_quickskip_possible) if (transparency_quickskip_possible || opacity_quickskip_possible)
{ {
@ -4484,6 +4493,19 @@ combine_sub_region (struct combine_regions_struct *st,
} }
/* else it's probably a brush-composite */ /* else it's probably a brush-composite */
/* use separate variables for the combining opacity and the opacity
* the layer mode is applied with since DISSLOVE_MODE "consumes"
* all opacity and wants to be applied OPAQUE
*/
layer_mode_opacity = opacity;
layer_mode_mask = m;
if (mode == GIMP_DISSOLVE_MODE)
{
opacity = OPAQUE_OPACITY;
m = NULL;
}
for (h = 0; h < src1->h; h++) for (h = 0; h < src1->h; h++)
{ {
hint = TILEROWHINT_UNDEFINED; hint = TILEROWHINT_UNDEFINED;
@ -4530,24 +4552,27 @@ combine_sub_region (struct combine_regions_struct *st,
{ {
/* Now, apply the paint mode */ /* Now, apply the paint mode */
struct apply_layer_mode_struct alms; struct apply_layer_mode_struct alms;
alms.src1 = s1;
alms.src2 = s2; alms.src1 = s1;
alms.dest = &s; alms.src2 = s2;
alms.x = src1->x; alms.mask = layer_mode_mask;
alms.y = src1->y + h; alms.dest = &s;
alms.opacity = opacity; alms.x = src1->x;
alms.y = src1->y + h;
alms.opacity = layer_mode_opacity;
alms.combine = combine; alms.combine = combine;
alms.length = src1->w; alms.length = src1->w;
alms.bytes1 = src1->bytes; alms.bytes1 = src1->bytes;
alms.bytes2 = src2->bytes; alms.bytes2 = src2->bytes;
/* Determine whether the alpha channel of the destination can be /* Determine whether the alpha channel of the destination can be
* affected by the specified mode--This keeps consistency with * affected by the specified mode--This keeps consistency with
* varying opacities * varying opacities
*/ */
mode_affect = layer_modes[mode].affect_alpha; mode_affect = layer_modes[mode].affect_alpha;
layer_mode_funcs[mode](&alms);
layer_mode_funcs[mode] (&alms);
combine = (alms.combine == NO_COMBINATION) ? type : alms.combine; combine = (alms.combine == NO_COMBINATION) ? type : alms.combine;
break; break;
} }
@ -4698,7 +4723,12 @@ combine_sub_region (struct combine_regions_struct *st,
s2 += src2->rowstride; s2 += src2->rowstride;
d += dest->rowstride; d += dest->rowstride;
if (mask) if (mask)
m += mask->rowstride; {
layer_mode_mask += mask->rowstride;
if (m)
m += mask->rowstride;
}
} }
} }