Thraka / SadConsole

A .NET ascii/ansi console engine written in C# for MonoGame and XNA. Create your own text roguelike (or other) games!
MIT License
1.22k stars 120 forks source link

Not possible to adjust decorator color without setting a new array #335

Closed Ven0maus closed 11 months ago

Ven0maus commented 11 months ago
/// <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 11 months ago

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

Ven0maus commented 11 months ago

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.

Ven0maus commented 11 months ago
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 11 months ago

@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 11 months ago

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