Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// <summary>
- /// Contains operations to blend colors together.
- /// </summary>
- public static class Blending
- {
- /// <summary>
- /// Describes the blending mode which should be applied
- /// </summary>
- public enum LayerMode :
- ushort
- {
- Normal,
- Screen,
- Overlay,
- Dodge,
- Burn,
- Add,
- Subtract,
- Multiply,
- Divide,
- Min,
- Max,
- Difference,
- }
- #region Blending.Apply
- public static void Apply(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count, LayerMode mode)
- {
- switch (mode)
- {
- case (LayerMode.Normal): Normal(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Screen): Screen(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Overlay): Overlay(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Dodge): Dodge(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Burn): Burn(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Add): Add(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Subtract): Subtract(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Multiply): Multiply(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Divide): Divide(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Min): Min(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Max): Max(source, sourceIndex, target, targetIndex, count); break;
- case (LayerMode.Difference): Difference(source, sourceIndex, target, targetIndex, count); break;
- }
- }
- public static void Apply(c32[] values, int index, int count, c32 other, LayerMode mode)
- {
- switch (mode)
- {
- case (LayerMode.Normal): Normal(values, index, count, other); break;
- case (LayerMode.Screen): Screen(values, index, count, other); break;
- case (LayerMode.Overlay): Overlay(values, index, count, other); break;
- case (LayerMode.Dodge): Dodge(values, index, count, other); break;
- case (LayerMode.Burn): Burn(values, index, count, other); break;
- case (LayerMode.Add): Add(values, index, count, other); break;
- case (LayerMode.Subtract): Subtract(values, index, count, other); break;
- case (LayerMode.Multiply): Multiply(values, index, count, other); break;
- case (LayerMode.Divide): Divide(values, index, count, other); break;
- case (LayerMode.Min): Min(values, index, count, other); break;
- case (LayerMode.Max): Max(values, index, count, other); break;
- case (LayerMode.Difference): Difference(values, index, count, other); break;
- }
- }
- public static c32 Apply(c32 value, c32 other, LayerMode mode)
- {
- switch (mode)
- {
- case (LayerMode.Normal): return Normal(value, other);
- case (LayerMode.Screen): return Screen(value, other);
- case (LayerMode.Overlay): return Overlay(value, other);
- case (LayerMode.Dodge): return Dodge(value, other);
- case (LayerMode.Burn): return Burn(value, other);
- case (LayerMode.Add): return Add(value, other);
- case (LayerMode.Subtract): return Subtract(value, other);
- case (LayerMode.Multiply): return Multiply(value, other);
- case (LayerMode.Divide): return Divide(value, other);
- case (LayerMode.Min): return Min(value, other);
- case (LayerMode.Max): return Max(value, other);
- case (LayerMode.Difference): return Difference(value, other);
- }
- return value;
- }
- #endregion
- #region Blending.Normal
- public static void Normal(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- return;
- }
- public static void Normal(c32[] values, int index, int count, c32 other)
- {
- return;
- }
- public static c32 Normal(c32 value, c32 other)
- {
- return value;
- }
- #endregion
- #region Blending.Screen
- public static void Screen(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- value.R = (byte)(0xFF - (0xFF - value.R) * (0xFF - other.R) / 0xFF);
- value.G = (byte)(0xFF - (0xFF - value.G) * (0xFF - other.G) / 0xFF);
- value.B = (byte)(0xFF - (0xFF - value.B) * (0xFF - other.B) / 0xFF);
- value.A = (byte)(0xFF - (0xFF - value.A) * (0xFF - other.A) / 0xFF);
- target[i + targetIndex] = value;
- }
- }
- public static void Screen(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- value.R = (byte)(0xFF - (0xFF - value.R) * (0xFF - other.R) / 0xFF);
- value.G = (byte)(0xFF - (0xFF - value.G) * (0xFF - other.G) / 0xFF);
- value.B = (byte)(0xFF - (0xFF - value.B) * (0xFF - other.B) / 0xFF);
- value.A = (byte)(0xFF - (0xFF - value.A) * (0xFF - other.A) / 0xFF);
- values[i + index] = value;
- }
- }
- public static c32 Screen(c32 value, c32 other)
- {
- value.R = (byte)(0xFF - (0xFF - value.R) * (0xFF - other.R) / 0xFF);
- value.G = (byte)(0xFF - (0xFF - value.G) * (0xFF - other.G) / 0xFF);
- value.B = (byte)(0xFF - (0xFF - value.B) * (0xFF - other.B) / 0xFF);
- value.A = (byte)(0xFF - (0xFF - value.A) * (0xFF - other.A) / 0xFF);
- return value;
- }
- #endregion
- #region Blending.Overlay
- public static void Overlay(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (value.R < 0x80)
- value.R = (byte)(value.R * other.R / 0x80);
- else
- value.R = (byte)(0xFF - (0xFF - value.R) * (0xFF - other.R) / 0x80);
- if (value.G < 0x80)
- value.G = (byte)(value.G * other.G / 0x80);
- else
- value.G = (byte)(0xFF - (0xFF - value.G) * (0xFF - other.G) / 0x80);
- if (value.B < 0x80)
- value.B = (byte)(value.B * other.B / 0x80);
- else
- value.B = (byte)(0xFF - (0xFF - value.B) * (0xFF - other.B) / 0x80);
- if (value.A < 0x80)
- value.A = (byte)(value.A * other.A / 0x80);
- else
- value.A = (byte)(0xFF - (0xFF - value.A) * (0xFF - other.A) / 0x80);
- target[i + targetIndex] = value;
- }
- }
- public static void Overlay(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (value.R < 0x80)
- value.R = (byte)(value.R * other.R / 0x80);
- else
- value.R = (byte)(0xFF - (0xFF - value.R) * (0xFF - other.R) / 0x80);
- if (value.G < 0x80)
- value.G = (byte)(value.G * other.G / 0x80);
- else
- value.G = (byte)(0xFF - (0xFF - value.G) * (0xFF - other.G) / 0x80);
- if (value.B < 0x80)
- value.B = (byte)(value.B * other.B / 0x80);
- else
- value.B = (byte)(0xFF - (0xFF - value.B) * (0xFF - other.B) / 0x80);
- if (value.A < 0x80)
- value.A = (byte)(value.A * other.A / 0x80);
- else
- value.A = (byte)(0xFF - (0xFF - value.A) * (0xFF - other.A) / 0x80);
- values[i + index] = value;
- }
- }
- public static c32 Overlay(c32 value, c32 other)
- {
- if (value.R < 0x80)
- value.R = (byte)(value.R * other.R / 0x80);
- else
- value.R = (byte)(0xFF - (0xFF - value.R) * (0xFF - other.R) / 0x80);
- if (value.G < 0x80)
- value.G = (byte)(value.G * other.G / 0x80);
- else
- value.G = (byte)(0xFF - (0xFF - value.G) * (0xFF - other.G) / 0x80);
- if (value.B < 0x80)
- value.B = (byte)(value.B * other.B / 0x80);
- else
- value.B = (byte)(0xFF - (0xFF - value.B) * (0xFF - other.B) / 0x80);
- if (value.A < 0x80)
- value.A = (byte)(value.A * other.A / 0x80);
- else
- value.A = (byte)(0xFF - (0xFF - value.A) * (0xFF - other.A) / 0x80);
- return value;
- }
- #endregion
- #region Blending.Dodge
- public static void Dodge(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (other.R == 0xFF) value.R = 0xFF; else value.R = (byte)Math.Min(0xFF, (0xFF * value.R / (0xFF - other.R)));
- if (other.G == 0xFF) value.G = 0xFF; else value.G = (byte)Math.Min(0xFF, (0xFF * value.G / (0xFF - other.G)));
- if (other.B == 0xFF) value.B = 0xFF; else value.B = (byte)Math.Min(0xFF, (0xFF * value.B / (0xFF - other.B)));
- if (other.A == 0xFF) value.A = 0xFF; else value.A = (byte)Math.Min(0xFF, (0xFF * value.A / (0xFF - other.A)));
- target[i + targetIndex] = value;
- }
- }
- public static void Dodge(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (other.R == 0xFF) value.R = 0xFF; else value.R = (byte)Math.Min(0xFF, (0xFF * value.R / (0xFF - other.R)));
- if (other.G == 0xFF) value.G = 0xFF; else value.G = (byte)Math.Min(0xFF, (0xFF * value.G / (0xFF - other.G)));
- if (other.B == 0xFF) value.B = 0xFF; else value.B = (byte)Math.Min(0xFF, (0xFF * value.B / (0xFF - other.B)));
- if (other.A == 0xFF) value.A = 0xFF; else value.A = (byte)Math.Min(0xFF, (0xFF * value.A / (0xFF - other.A)));
- values[i + index] = value;
- }
- }
- public static c32 Dodge(c32 value, c32 other)
- {
- if (other.R == 0xFF) value.R = 0xFF; else value.R = (byte)Math.Min(0xFF, (0xFF * value.R / (0xFF - other.R)));
- if (other.G == 0xFF) value.G = 0xFF; else value.G = (byte)Math.Min(0xFF, (0xFF * value.G / (0xFF - other.G)));
- if (other.B == 0xFF) value.B = 0xFF; else value.B = (byte)Math.Min(0xFF, (0xFF * value.B / (0xFF - other.B)));
- if (other.A == 0xFF) value.A = 0xFF; else value.A = (byte)Math.Min(0xFF, (0xFF * value.A / (0xFF - other.A)));
- return value;
- }
- #endregion
- #region Blending.Burn
- public static void Burn(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (other.R == 0x00) value.R = 0x00; else value.R = (byte)Math.Max(0x00, (0xFF - (0xFF - value.R) * 0xFF / other.R));
- if (other.G == 0x00) value.G = 0x00; else value.G = (byte)Math.Max(0x00, (0xFF - (0xFF - value.G) * 0xFF / other.G));
- if (other.B == 0x00) value.B = 0x00; else value.B = (byte)Math.Max(0x00, (0xFF - (0xFF - value.B) * 0xFF / other.B));
- if (other.A == 0x00) value.A = 0x00; else value.A = (byte)Math.Max(0x00, (0xFF - (0xFF - value.A) * 0xFF / other.A));
- target[i + targetIndex] = value;
- }
- }
- public static void Burn(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (other.R == 0x00) value.R = 0x00; else value.R = (byte)Math.Max(0x00, (0xFF - (0xFF - value.R) * 0xFF / other.R));
- if (other.G == 0x00) value.G = 0x00; else value.G = (byte)Math.Max(0x00, (0xFF - (0xFF - value.G) * 0xFF / other.G));
- if (other.B == 0x00) value.B = 0x00; else value.B = (byte)Math.Max(0x00, (0xFF - (0xFF - value.B) * 0xFF / other.B));
- if (other.A == 0x00) value.A = 0x00; else value.A = (byte)Math.Max(0x00, (0xFF - (0xFF - value.A) * 0xFF / other.A));
- values[i + index] = value;
- }
- }
- public static c32 Burn(c32 value, c32 other)
- {
- if (other.R == 0x00) value.R = 0x00; else value.R = (byte)Math.Max(0x00, (0xFF - (0xFF - value.R) * 0xFF / other.R));
- if (other.G == 0x00) value.G = 0x00; else value.G = (byte)Math.Max(0x00, (0xFF - (0xFF - value.G) * 0xFF / other.G));
- if (other.B == 0x00) value.B = 0x00; else value.B = (byte)Math.Max(0x00, (0xFF - (0xFF - value.B) * 0xFF / other.B));
- if (other.A == 0x00) value.A = 0x00; else value.A = (byte)Math.Max(0x00, (0xFF - (0xFF - value.A) * 0xFF / other.A));
- return value;
- }
- #endregion
- #region Blending.Add
- public static void Add(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (value.R + other.R < 0xFF) value.R += other.R; else value.R = 0xFF;
- if (value.G + other.G < 0xFF) value.G += other.G; else value.G = 0xFF;
- if (value.B + other.B < 0xFF) value.B += other.B; else value.B = 0xFF;
- if (value.A + other.A < 0xFF) value.A += other.A; else value.A = 0xFF;
- target[i + targetIndex] = value;
- }
- }
- public static void Add(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (value.R + other.R < 0xFF) value.R += other.R; else value.R = 0xFF;
- if (value.G + other.G < 0xFF) value.G += other.G; else value.G = 0xFF;
- if (value.B + other.B < 0xFF) value.B += other.B; else value.B = 0xFF;
- if (value.A + other.A < 0xFF) value.A += other.A; else value.A = 0xFF;
- values[i + index] = value;
- }
- }
- public static c32 Add(c32 value, c32 other)
- {
- if (value.R + other.R < 0xFF) value.R += other.R; else value.R = 0xFF;
- if (value.G + other.G < 0xFF) value.G += other.G; else value.G = 0xFF;
- if (value.B + other.B < 0xFF) value.B += other.B; else value.B = 0xFF;
- if (value.A + other.A < 0xFF) value.A += other.A; else value.A = 0xFF;
- return value;
- }
- #endregion
- #region Blending.Subtract
- public static void Subtract(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (value.R > other.R) value.R -= other.R; else value.R = 0x00;
- if (value.G > other.G) value.G -= other.G; else value.G = 0x00;
- if (value.B > other.B) value.B -= other.B; else value.B = 0x00;
- if (value.A > other.A) value.A -= other.R; else value.A = 0x00;
- target[i + targetIndex] = value;
- }
- }
- public static void Subtract(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (value.R > other.R) value.R -= other.R; else value.R = 0x00;
- if (value.G > other.G) value.G -= other.G; else value.G = 0x00;
- if (value.B > other.B) value.B -= other.B; else value.B = 0x00;
- if (value.A > other.A) value.A -= other.R; else value.A = 0x00;
- values[i + index] = value;
- }
- }
- public static c32 Subtract(c32 value, c32 other)
- {
- if (value.R > other.R) value.R -= other.R; else value.R = 0x00;
- if (value.G > other.G) value.G -= other.G; else value.G = 0x00;
- if (value.B > other.B) value.B -= other.B; else value.B = 0x00;
- if (value.A > other.A) value.A -= other.R; else value.A = 0x00;
- return value;
- }
- #endregion
- #region Blending.Multiply
- public static void Multiply(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- value.R = (byte)(value.R * other.R / 0xFF);
- value.G = (byte)(value.G * other.G / 0xFF);
- value.B = (byte)(value.B * other.B / 0xFF);
- value.A = (byte)(value.A * other.A / 0xFF);
- target[i + targetIndex] = value;
- }
- }
- public static void Multiply(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- value.R = (byte)(value.R * other.R / 0xFF);
- value.G = (byte)(value.G * other.G / 0xFF);
- value.B = (byte)(value.B * other.B / 0xFF);
- value.A = (byte)(value.A * other.A / 0xFF);
- values[i + index] = value;
- }
- }
- public static c32 Multiply(c32 value, c32 other)
- {
- value.R = (byte)(value.R * other.R / 0xFF);
- value.G = (byte)(value.G * other.G / 0xFF);
- value.B = (byte)(value.B * other.B / 0xFF);
- value.A = (byte)(value.A * other.A / 0xFF);
- return value;
- }
- #endregion
- #region Blending.Divide
- public static void Divide(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (other.R == 0x00) value.R = 0xFF; else value.R = (byte)Math.Min(0xFF, (value.R * 0xFF / other.R));
- if (other.R == 0x00) value.G = 0xFF; else value.G = (byte)Math.Min(0xFF, (value.G * 0xFF / other.G));
- if (other.R == 0x00) value.B = 0xFF; else value.B = (byte)Math.Min(0xFF, (value.B * 0xFF / other.B));
- if (other.R == 0x00) value.A = 0xFF; else value.A = (byte)Math.Min(0xFF, (value.A * 0xFF / other.A));
- target[i + targetIndex] = value;
- }
- }
- public static void Divide(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (other.R == 0x00) value.R = 0xFF; else value.R = (byte)Math.Min(0xFF, (value.R * 0xFF / other.R));
- if (other.R == 0x00) value.G = 0xFF; else value.G = (byte)Math.Min(0xFF, (value.G * 0xFF / other.G));
- if (other.R == 0x00) value.B = 0xFF; else value.B = (byte)Math.Min(0xFF, (value.B * 0xFF / other.B));
- if (other.R == 0x00) value.A = 0xFF; else value.A = (byte)Math.Min(0xFF, (value.A * 0xFF / other.A));
- values[i + index] = value;
- }
- }
- public static c32 Divide(c32 value, c32 other)
- {
- if (other.R == 0x00) value.R = 0xFF; else value.R = (byte)Math.Min(0xFF, (value.R * 0xFF / other.R));
- if (other.R == 0x00) value.G = 0xFF; else value.G = (byte)Math.Min(0xFF, (value.G * 0xFF / other.G));
- if (other.R == 0x00) value.B = 0xFF; else value.B = (byte)Math.Min(0xFF, (value.B * 0xFF / other.B));
- if (other.R == 0x00) value.A = 0xFF; else value.A = (byte)Math.Min(0xFF, (value.A * 0xFF / other.A));
- return value;
- }
- #endregion
- #region Blending.Min
- public static void Min(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (value.R > other.R) value.R = other.R;
- if (value.G > other.G) value.G = other.G;
- if (value.B > other.B) value.B = other.B;
- if (value.A > other.A) value.A = other.A;
- target[i + targetIndex] = value;
- }
- }
- public static void Min(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (value.R > other.R) value.R = other.R;
- if (value.G > other.G) value.G = other.G;
- if (value.B > other.B) value.B = other.B;
- if (value.A > other.A) value.A = other.A;
- values[i + index] = value;
- }
- }
- public static c32 Min(c32 value, c32 other)
- {
- if (value.R > other.R) value.R = other.R;
- if (value.G > other.G) value.G = other.G;
- if (value.B > other.B) value.B = other.B;
- if (value.A > other.A) value.A = other.A;
- return value;
- }
- #endregion
- #region Blending.Max
- public static void Max(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (value.R < other.R) value.R = other.R;
- if (value.G < other.G) value.G = other.G;
- if (value.B < other.B) value.B = other.B;
- if (value.A < other.A) value.A = other.A;
- target[i + targetIndex] = value;
- }
- }
- public static void Max(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (value.R < other.R) value.R = other.R;
- if (value.G < other.G) value.G = other.G;
- if (value.B < other.B) value.B = other.B;
- if (value.A < other.A) value.A = other.A;
- values[i + index] = value;
- }
- }
- public static c32 Max(c32 value, c32 other)
- {
- if (value.R < other.R) value.R = other.R;
- if (value.G < other.G) value.G = other.G;
- if (value.B < other.B) value.B = other.B;
- if (value.A < other.A) value.A = other.A;
- return value;
- }
- #endregion
- #region Blending.Difference
- public static void Difference(c32[] source, int sourceIndex, c32[] target, int targetIndex, int count)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = source[i + sourceIndex];
- c32 other = target[i + targetIndex];
- if (value.R > other.R) value.R -= other.R; else value.R = (byte)(other.R - value.R);
- if (value.G > other.G) value.G -= other.G; else value.G = (byte)(other.G - value.G);
- if (value.B > other.B) value.B -= other.B; else value.B = (byte)(other.B - value.B);
- if (value.A > other.A) value.A -= other.A; else value.A = (byte)(other.A - value.A);
- target[i + targetIndex] = value;
- }
- }
- public static void Difference(c32[] values, int index, int count, c32 other)
- {
- for (int i = 0; i < count; i++)
- {
- c32 value = values[i + index];
- if (value.R > other.R) value.R -= other.R; else value.R = (byte)(other.R - value.R);
- if (value.G > other.G) value.G -= other.G; else value.G = (byte)(other.G - value.G);
- if (value.B > other.B) value.B -= other.B; else value.B = (byte)(other.B - value.B);
- if (value.A > other.A) value.A -= other.A; else value.A = (byte)(other.A - value.A);
- values[i + index] = value;
- }
- }
- public static c32 Difference(c32 value, c32 other)
- {
- if (value.R > other.R) value.R -= other.R; else value.R = (byte)(other.R - value.R);
- if (value.G > other.G) value.G -= other.G; else value.G = (byte)(other.G - value.G);
- if (value.B > other.B) value.B -= other.B; else value.B = (byte)(other.B - value.B);
- if (value.A > other.A) value.A -= other.A; else value.A = (byte)(other.A - value.A);
- return value;
- }
- #endregion
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement