317 lines
8.1 KiB
C#
317 lines
8.1 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot;
|
|
using System;
|
|
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
public class TextureCombinerBuffer
|
|
{
|
|
int _width;
|
|
public int width => _width;
|
|
|
|
int _height;
|
|
public int height => _height;
|
|
|
|
Color[] _pixels;
|
|
|
|
public int numPixels => _pixels.Length;
|
|
|
|
public static TextureCombinerBuffer Create( int w, int h )
|
|
{
|
|
var tb = new TextureCombinerBuffer();
|
|
tb._height = h;
|
|
tb._width = w;
|
|
tb._pixels = new Color[ w * h ];
|
|
|
|
return tb;
|
|
}
|
|
|
|
public void UnblendBlack( float treshold = 10f/255f )
|
|
{
|
|
for ( int i = 0; i < _pixels.Length; i++ )
|
|
{
|
|
_pixels[ i ] = _pixels[ i ].UnblendBlack( treshold );
|
|
}
|
|
}
|
|
|
|
public void Fill( Color color, int x, int y, int w, int h )
|
|
{
|
|
for ( int i = 0; i < w; i++ )
|
|
{
|
|
for ( int j = 0; j < h; j++ )
|
|
{
|
|
SetAt( i + x, j + y, color );
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Fill( Color color )
|
|
{
|
|
Fill( color, 0, 0, width, height );
|
|
}
|
|
|
|
public static TextureCombinerBuffer From( Texture2D texture, int srgbConversion = 0 )
|
|
{
|
|
var buffer = Create( texture.GetWidth(), texture.GetHeight() );
|
|
buffer.CopyFrom( texture.GetImage(), 0, 0, 0, 0, texture.GetWidth(), texture.GetHeight(), srgbConversion);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
public void CopyFromSampled( TextureCombinerBuffer source, int x, int y, int w, int h )
|
|
{
|
|
RJLog.Log( "Copy Sampled", x,y, w, h );
|
|
|
|
for ( int i = 0; i < w; i ++ )
|
|
{
|
|
for ( int j = 0; j < h; j++ )
|
|
{
|
|
float u = i / (float)( w );
|
|
float v = j / (float)( h );
|
|
|
|
var sourceX = Mathf.RoundToInt( u * source.width );
|
|
var sourceY = Mathf.RoundToInt( v * source.height );
|
|
|
|
var color = source.GetAt( sourceX, sourceY );
|
|
SetAt( x + i, y + j, color );
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Texture2D GridMerge( int w, int h, Color background, bool alpha, bool mipMaps,
|
|
Vector2I alignment,
|
|
List<Texture2D> textures, List<Color> nullTextureColors )
|
|
{
|
|
|
|
var positions = new List<Vector2I>();
|
|
var sizes = new List<Vector2I>();
|
|
|
|
var mergeSize = new Vector2( w, h );
|
|
var gridSize = (Vector2I)( mergeSize / alignment );
|
|
|
|
RJLog.Log( "GridMerge" );
|
|
|
|
for ( int i = 0; i < textures.Count; i++ )
|
|
{
|
|
var box = TextureMerger.GetUVAlignmentBoxFor( alignment, i );
|
|
var position = (Vector2I) ( box.min * mergeSize );
|
|
positions.Add( position );
|
|
sizes.Add( gridSize );
|
|
|
|
RJLog.Log( i, position, gridSize );
|
|
}
|
|
|
|
|
|
|
|
return Merge( w, h, background, alpha, mipMaps, textures, nullTextureColors, positions, sizes );
|
|
}
|
|
|
|
public static Texture2D Merge( int w, int h, Color background, bool alpha, bool mipMaps,
|
|
List<Texture2D> textures, List<Color> nullTextureColors, List<Vector2I> positions, List<Vector2I> sizes )
|
|
{
|
|
var buffer = Create( w, h );
|
|
|
|
buffer.Fill( background );
|
|
|
|
for ( int i = 0; i < textures.Count; i++ )
|
|
{
|
|
var position = positions[ i ];
|
|
var size = sizes[ i ];
|
|
|
|
if ( textures[ i ] == null )
|
|
{
|
|
buffer.Fill( nullTextureColors[ i ], position.X, position.Y, size.X, size.Y );
|
|
continue;
|
|
}
|
|
|
|
var imageBuffer = From( textures[ i ] );
|
|
buffer.CopyFromSampled( imageBuffer, position.X, position.Y, size.X, size.Y );
|
|
}
|
|
|
|
return buffer.CreateImageTexture( alpha, mipMaps );
|
|
}
|
|
|
|
public ImageTexture CreateImageTexture( bool alpha = true, bool generateMipmaps = false )
|
|
{
|
|
var image = Image.CreateEmpty( width, height, generateMipmaps, alpha ? Image.Format.Rgba8 : Image.Format.Rgb8);
|
|
CopyTo( 0, 0, 0, 0, width, height, image, alpha );
|
|
|
|
if ( generateMipmaps )
|
|
{
|
|
image.GenerateMipmaps();
|
|
}
|
|
|
|
return ImageTexture.CreateFromImage( image );
|
|
}
|
|
|
|
public TextureCombinerBuffer Resize( int w, int h )
|
|
{
|
|
var buffer = Create( w, h );
|
|
|
|
for ( int i = 0; i < w; i++ )
|
|
{
|
|
for ( int j = 0; j < h; j++ )
|
|
{
|
|
var uv = new Vector2( i / (float) w, j / (float) h );
|
|
var pixel = SampleBilinearUV( uv );
|
|
|
|
buffer.SetAt( i, j, pixel );
|
|
}
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
public void CopyFrom( Image image, int sourceX, int sourceY, int ownX, int ownY, int w, int h, int srgbConversion = 0 )
|
|
{
|
|
if ( srgbConversion != 0 )
|
|
{
|
|
var gamma = Mathf.Pow( 2.2f, srgbConversion );
|
|
|
|
for ( int i = 0; i < w; i++ )
|
|
{
|
|
for ( int j = 0; j < h; j++ )
|
|
{
|
|
var sourcePixel = image == null ? new Color( 0, 0, 0 ) : image.GetPixel( sourceX + i, sourceY + j );
|
|
sourcePixel = sourcePixel.Gamma( gamma );
|
|
SetAt( ownX + i, ownY + j, sourcePixel );
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
for ( int i = 0; i < w; i++ )
|
|
{
|
|
for ( int j = 0; j < h; j++ )
|
|
{
|
|
var sourcePixel = image == null ? new Color( 0, 0, 0 ) : image.GetPixel( sourceX + i, sourceY + j );
|
|
SetAt( ownX + i, ownY + j, sourcePixel );
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void CopyTo( int ownX, int ownY, int targetX, int targetY, int w, int h, TextureCombinerBuffer output )
|
|
{
|
|
for ( int i = 0; i < w; i++ )
|
|
{
|
|
for ( int j = 0; j < h; j++ )
|
|
{
|
|
var ownPixel = GetAt( ownX + i, ownY + j );
|
|
|
|
output.SetAt( targetX + i, targetY + j, ownPixel );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public void CopyTo( int ownX, int ownY, int targetX, int targetY, int w, int h, Image image, bool alpha = true )
|
|
{
|
|
if ( ! alpha )
|
|
{
|
|
for ( int i = 0; i < w; i++ )
|
|
{
|
|
for ( int j = 0; j < h; j++ )
|
|
{
|
|
var ownPixel = GetAt( ownX + i, ownY + j );
|
|
ownPixel.A = 1;
|
|
image.SetPixel( targetX + i, targetY + j, ownPixel );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( int i = 0; i < w; i++ )
|
|
{
|
|
for ( int j = 0; j < h; j++ )
|
|
{
|
|
var ownPixel = GetAt( ownX + i, ownY + j );
|
|
image.SetPixel( targetX + i, targetY + j, ownPixel );
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public int ComputeIndexFromPosition( int x, int y )
|
|
{
|
|
return x + y * _width;
|
|
}
|
|
|
|
public Vector2I ComputePositionFromIndex( int index )
|
|
{
|
|
var x = index % width;
|
|
var y = index / width;
|
|
|
|
return new Vector2I( x, y );
|
|
}
|
|
|
|
public void SetAt( int x, int y, Color value )
|
|
{
|
|
SetIndexed( ComputeIndexFromPosition( x, y ), value );
|
|
}
|
|
|
|
public void SetIndexed( int index, Color value )
|
|
{
|
|
_pixels[ index ] = value;
|
|
}
|
|
|
|
public Color GetAt( int x, int y )
|
|
{
|
|
return GetIndexed( ComputeIndexFromPosition( x, y ) );
|
|
}
|
|
|
|
public Color GetIndexed( int index )
|
|
{
|
|
return _pixels[ index ];
|
|
}
|
|
|
|
public Color SampleNearestUV( Vector2 uv )
|
|
{
|
|
return SampleNearestImage( uv.X * width, uv.Y * height );
|
|
}
|
|
|
|
public Color SampleNearestImage( float imageDimensionsX, float imageDimensionsY )
|
|
{
|
|
return GetAt( Mathf.RoundToInt( imageDimensionsX ), Mathf.RoundToInt( imageDimensionsY ) );
|
|
}
|
|
|
|
public Color SampleBilinearUV( Vector2 uv )
|
|
{
|
|
return SampleBilinearImage( uv.X * width, uv.Y * height );
|
|
}
|
|
|
|
public Color SampleBilinearImage( float imageDimensionsX, float imageDimensionsY )
|
|
{
|
|
var lowX = Mathf.FloorToInt( imageDimensionsX );
|
|
var highX = Mathf.Min( lowX + 1, width - 1 );
|
|
var lerpX = imageDimensionsX - lowX;
|
|
|
|
|
|
|
|
var lowY = Mathf.FloorToInt( imageDimensionsY );
|
|
var highY = Mathf.Min( lowY + 1, height - 1 );
|
|
var lerpY = imageDimensionsY - lowY;
|
|
|
|
|
|
var ll = GetAt( lowX, lowY );
|
|
var hl = GetAt( highX, lowY );
|
|
|
|
var lh = GetAt( lowX, highY );
|
|
var hh = GetAt( highX, highY );
|
|
|
|
var upper = ll.Lerp( hl, lerpX );
|
|
var lower = lh.Lerp( hh, lerpX );
|
|
|
|
return upper.Lerp( lower, lerpY );
|
|
}
|
|
}
|
|
} |