Thraka/SadConsole

Not possible to adjust decorator color without setting a new array

Ven0maus opened this issue · 5 comments

/// <summary>
/// Sets the foreground alpha on each glyph on the surface that has a valid glyph
/// </summary>
/// <param name="alpha">0.0 - 1.0 where 1 is invisible</param>
private void SetGlyphsAlpha(double alpha)
{
	for (int x = 0; x < _surface.Width; x++)
	{
		for (int y = 0; y < _surface.Height; y++)
		{
			var foreground = _surface.Surface[x, y].Foreground;
			var background = _surface.Surface[x, y].Background;
			_surface.Surface[x, y].Foreground = foreground.SetAlpha(ClampTo0_255(alpha));
			_surface.Surface[x, y].Background = background.SetAlpha(ClampTo0_255(alpha));
		}
	}
	_surface.IsDirty = true;
}

private static byte ClampTo0_255(double value)
{
	double scaledValue = value * 255.0;
	int roundedValue = (int)Math.Round(scaledValue);
	byte clampedValue = (byte)Math.Max(0, Math.Min(255, roundedValue));
	return clampedValue;
}

Not possible to efficiently adjust decorator color without setting a new decorator array.

Thraka commented
  • Which version are you using?
  • Which host renderer are you using?

I looked at the monogame (linked below) and the SFML code but they both keep everything inside of the cell.IsVisible check.

https://github.com/Thraka/SadConsole/blob/develop/SadConsole.Host.MonoGame/Renderers/Steps/SurfaceRenderStep.cs#L88-L100

Oh wait I see what is happening, I noticed it during my scene transition fade effect. What I'm doing is fading the alpha on the foreground and background color of the surface cell.
I suppose the only way to fade the decorator is to set a new array of decorators on each step (since the color is a readonly field)
I'm afraid it might give some GC overhead..

I've updated the github issue, to reflect the real problem.

private static CellDecorator[] AdjustDecoratorsColor(CellDecorator[] decorators, byte alpha)
{
	if (decorators == null || decorators.Length == 0) return decorators;
	CellDecorator[] newDecorators = new CellDecorator[decorators.Length];
	for (int i=0; i < decorators.Length; i++)
	{
		var dec = decorators[i];
		newDecorators[i] = new CellDecorator(dec.Color.SetAlpha(alpha), dec.Glyph, dec.Mirror);
	}
	return newDecorators;
}
        
 _surface.Surface[x, y].Decorators = AdjustDecoratorsColor(_surface.Surface[x, y].Decorators, ClampTo0_255(alpha));

This works but needs to be profiled to see how much impact this has if it runs as like an effect for example.

Thraka commented

@Ven0maus actually I can alter the structure a bit for the next alpha release. Since SadConsole is .NET 6, I can convert the struct members from fields to properties and add { get; init; } which lets you do nondestructive mutation. This lets you do this (considering the next alpha will use lists instead of arrays for decorators. Here's an extension method for a surface:

public static void SetDecoratorAlpha(this ISurface obj, int x, int y, byte alpha)
{
    if (obj.IsValidCell(x, y, out int index) && obj.Surface[index].Decorators != null)
    {
        for (int i = 0; i < obj.Surface[index].Decorators!.Count; i++)
        {
            CellDecorator temp = obj.Surface[index].Decorators![i];

            obj.Surface[index].Decorators![i] = temp with { Color = temp.Color.SetAlpha(alpha) };
        }
    }
}
Thraka commented

Closing as not a bug. The decorator enhancements have been pushed to the develop branch that let you mutate a decorator.