254 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C#
		
	
	
	
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
using Godot;
 | 
						|
using System;
 | 
						|
using System.Threading.Tasks;
 | 
						|
 | 
						|
using System.Linq;
 | 
						|
using TriangleNet.Geometry;
 | 
						|
 | 
						|
namespace Rokojori
 | 
						|
{
 | 
						|
  public class CPUTextureDilater
 | 
						|
  {
 | 
						|
    public static async Task<Texture2D> Dilate( Texture2D texture, Func<Task> waiting, float alphaTreshold = 250f/255f )
 | 
						|
    {
 | 
						|
      var dilater = new CPUTextureDilater();
 | 
						|
      dilater.alphaTreshold = alphaTreshold;
 | 
						|
      dilater.waiting = waiting;
 | 
						|
 | 
						|
      var t = await dilater._Dilate( texture );
 | 
						|
 | 
						|
      return t;
 | 
						|
    }
 | 
						|
 | 
						|
    TextureCombinerBuffer _buffer;
 | 
						|
    Func<Task> waiting;
 | 
						|
 | 
						|
    async Task<Texture2D> _Dilate( Texture2D texture )
 | 
						|
    {
 | 
						|
      _buffer = TextureCombinerBuffer.From( texture );
 | 
						|
 | 
						|
      await _Process();
 | 
						|
 | 
						|
      return _buffer.CreateImageTexture();
 | 
						|
    }
 | 
						|
 | 
						|
    public float alphaTreshold = 250f/255f;
 | 
						|
 | 
						|
    HashSet<int> _processed = new HashSet<int>();
 | 
						|
    HashSet<int> _unprocessed = new HashSet<int>();
 | 
						|
    HashSet<int> _edges = new HashSet<int>();
 | 
						|
 | 
						|
    
 | 
						|
 | 
						|
    async Task _Process()
 | 
						|
    {
 | 
						|
      _buffer.UnblendBlack();
 | 
						|
 | 
						|
      GrabInitialPixels();
 | 
						|
      
 | 
						|
 | 
						|
      if ( _unprocessed.Count == _buffer.numPixels )
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      int maxMessages = 100;
 | 
						|
      int messageCounter = 0;
 | 
						|
      int messageLimit = 200000;
 | 
						|
 | 
						|
      int max = 1000 * 1000;
 | 
						|
      int it = 0;
 | 
						|
 | 
						|
      var random = LCG.WithSeed( 1984 );
 | 
						|
 | 
						|
      while ( _edges.Count > 0 && it < max )
 | 
						|
      {
 | 
						|
        it++;
 | 
						|
 | 
						|
        if ( messageCounter >= messageLimit )
 | 
						|
        {
 | 
						|
          await waiting();
 | 
						|
          messageCounter = 0;
 | 
						|
          RJLog.Log( 
 | 
						|
            RegexUtility._FF( 100f *_processed.Count / _buffer.numPixels ) + "%",
 | 
						|
            "Valid: ", ( _processed.Count + _edges.Count + _unprocessed.Count ) == _buffer.numPixels,
 | 
						|
            "P", _processed.Count, "E",_edges.Count, "U", _unprocessed.Count 
 | 
						|
          );
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          messageCounter ++;
 | 
						|
        }
 | 
						|
 | 
						|
        var edge = _edges.ElementAt( random.IntegerExclusive( _edges.Count ) );
 | 
						|
        _edges.Remove( edge );
 | 
						|
 | 
						|
        if ( ! _processed.Contains( edge ) )
 | 
						|
        {
 | 
						|
          var edgeColor = ComputeColor( edge );
 | 
						|
          _processed.Add( edge );
 | 
						|
          _buffer.SetIndexed( edge, edgeColor );
 | 
						|
        }
 | 
						|
 | 
						|
        AddEdgeNeighbors( edge );
 | 
						|
        
 | 
						|
      }
 | 
						|
 | 
						|
      if ( _edges.Count > 0 && it == max )
 | 
						|
      {
 | 
						|
        RJLog.Log( "Aborted, too many entries" );
 | 
						|
      }
 | 
						|
      
 | 
						|
    }
 | 
						|
 | 
						|
    void GrabInitialPixels()
 | 
						|
    {
 | 
						|
      for ( int i = 0; i < _buffer.numPixels; i++ )
 | 
						|
      {
 | 
						|
        if ( ! HasColor( i ) )
 | 
						|
        {
 | 
						|
          _unprocessed.Add( i );          
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          if ( IsEdge( i ) )
 | 
						|
          {
 | 
						|
            _edges.Add( i );
 | 
						|
          }
 | 
						|
 | 
						|
          _processed.Add( i );
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    void AddEdgeNeighbors( int i )
 | 
						|
    {
 | 
						|
      var position = _buffer.ComputePositionFromIndex( i );
 | 
						|
 | 
						|
      for ( int x = -1; x <= 1; x++ )
 | 
						|
      {
 | 
						|
        for ( int y = -1; y <= 1; y++ )
 | 
						|
        {
 | 
						|
          if ( x == 0 && y == 0 )
 | 
						|
          {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          var index = _buffer.ComputeIndexFromPosition( position.X + x, position.Y + y );
 | 
						|
 | 
						|
          if ( index < 0 || index >= _buffer.numPixels )
 | 
						|
          {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          if ( ! _unprocessed.Contains( index ) )
 | 
						|
          {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          _unprocessed.Remove( index );
 | 
						|
          _edges.Add( index );
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    bool HasColor( int x, int y  )
 | 
						|
    {
 | 
						|
      return HasColor( _buffer.ComputeIndexFromPosition( x, y ) );
 | 
						|
    }
 | 
						|
 | 
						|
    bool HasColor( int i )
 | 
						|
    {
 | 
						|
      if ( i < 0 || i >= _buffer.numPixels )
 | 
						|
      {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      var pixel = _buffer.GetIndexed( i );
 | 
						|
      
 | 
						|
      if ( pixel.A > alphaTreshold )
 | 
						|
      {
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
 | 
						|
      return _processed.Contains( i );
 | 
						|
    } 
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    bool IsEdge( int i )
 | 
						|
    {
 | 
						|
      if ( ! HasColor( i ) )
 | 
						|
      {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      var position = _buffer.ComputePositionFromIndex( i );     
 | 
						|
 | 
						|
      for ( int x = -1; x <= 1; x++ )
 | 
						|
      {
 | 
						|
        for ( int y = -1; y <= 1; y++ )
 | 
						|
        {
 | 
						|
          if ( x == 0 && y == 0 )
 | 
						|
          {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          if ( ! HasColor( position.X + x, position.Y + y ) )
 | 
						|
          { 
 | 
						|
            return true;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      return false;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    Color ComputeColor( int i )
 | 
						|
    {
 | 
						|
      var position = _buffer.ComputePositionFromIndex( i );
 | 
						|
 | 
						|
      var pixel = _buffer.GetIndexed( i ); 
 | 
						|
      var distance = 10f;
 | 
						|
      var closestPixel = -1;
 | 
						|
 | 
						|
      for ( int x = -1; x <= 1; x++ )
 | 
						|
      {
 | 
						|
        for ( int y = -1; y <= 1; y++ )
 | 
						|
        {
 | 
						|
          if ( ( x == 0 && y == 0 ) || ! HasColor( position.X + x, position.Y + y ) )
 | 
						|
          {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          var d = new Vector2( x, y ).Length();
 | 
						|
 | 
						|
          if ( d >= distance )
 | 
						|
          {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          distance = d;
 | 
						|
          closestPixel = _buffer.ComputeIndexFromPosition( position.X + x, position.Y + y );
 | 
						|
 | 
						|
          // var pixelColor = _buffer.GetAt( position.X + x, position.Y + y );
 | 
						|
          // rawColor += new Vector3( pixelColor.R, pixelColor.G, pixelColor.B);
 | 
						|
          // numColors ++;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      // rawColor /= numColors;
 | 
						|
 | 
						|
      var rawColor = _buffer.GetIndexed( closestPixel );
 | 
						|
 | 
						|
      
 | 
						|
 | 
						|
      return new Color( rawColor.R, rawColor.G, rawColor.B, pixel.A );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
} |