public unsafe void ComputeSAT( System.IO.FileInfo _FileName, System.IO.FileInfo _TargetFileName ) {
int W, H;
byte[] Content = null;
using ( System.IO.FileStream S = _FileName.OpenRead() )
using ( Bitmap B = Bitmap.FromStream( S ) as Bitmap )
{
W = B.Width;
H = B.Height;
Content = new byte[W*H*4];
BitmapData LockedBitmap = B.LockBits( new Rectangle( 0, 0, W, H ), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb );
for ( int Y=0; Y < H; Y++ )
{
byte* pScanline = (byte*) LockedBitmap.Scan0 + Y * LockedBitmap.Stride;
int Offset = 4*W*Y;
for ( int X=0; X < W; X++, Offset+=4 )
{
Content[Offset+2] = *pScanline++; // B
Content[Offset+1] = *pScanline++; // G
Content[Offset+0] = *pScanline++; // R
Content[Offset+3] = *pScanline++; // A
}
}
B.UnlockBits( LockedBitmap );
}
// Build the float4 image
float4[,] Image = new float4[W,H];
for ( int Y=0; Y < H; Y++ ) {
for ( int X=0; X < W; X++ ) {
Image[X,Y] = new float4( Content[4*(W*Y+X)+0] / 255.0f, Content[4*(W*Y+X)+1] / 255.0f, Content[4*(W*Y+X)+2] / 255.0f, 0.0f );
// Linearize from gamma space
Image[X,Y].x = (float) Math.Pow( Image[X,Y].x, 2.2 );
Image[X,Y].y = (float) Math.Pow( Image[X,Y].y, 2.2 );
Image[X,Y].z = (float) Math.Pow( Image[X,Y].z, 2.2 );
}
}
//////////////////////////////////////////////////////////////////////////
// Build mips and save as a simple format
{
int MaxSize = Math.Max( W, H );
int MipsCount = (int) (Math.Ceiling( Math.Log( MaxSize+1 ) / Math.Log( 2 ) ));
float4[][,] Mips = new float4[MipsCount][,];
Mips[0] = Image;
int TargetWidth = W;
int TargetHeight = H;
for ( int MipLevel=1; MipLevel < Mips.Length; MipLevel++ ) {
TargetWidth = Math.Max( 1, TargetWidth >> 1 );
TargetHeight = Math.Max( 1, TargetHeight >> 1 );
float MipPixelSizeX = W / TargetWidth; // Size of a mip pixel; in amount of original image pixels (i.e. mip #0)
float MipPixelSizeY = H / TargetHeight; // Size of a mip pixel; in amount of original image pixels (i.e. mip #0)
int KernelSize = 2 * (int) Math.Pow( 2, MipLevel );
float Sigma = (float) Math.Sqrt( -KernelSize*KernelSize / (2.0 * Math.Log( 0.01 )) ); // So we have a weight of 0.01 at a Kernel Size distance
float[] KernelFactors = new float[1+KernelSize];
float SumWeights = 0.0f;
for ( int i=0; i <= KernelSize; i++ ) {
KernelFactors[i] = (float) (Math.Exp( -i*i / (2.0 * Sigma * Sigma)) / Math.Sqrt( 2 * Math.PI * Sigma * Sigma ) );
SumWeights += KernelFactors[i];
}
// Perform a horizontal blur first
float4[,] Source = Image;
float4[,] Target = new float4[TargetWidth,H];
for ( int Y=0; Y < H; Y++ ) {
for ( int X=0; X < TargetWidth; X++ ) {
float CenterX = X * MipPixelSizeX + 0.5f * (MipPixelSizeX-1);
float4 Sum = KernelFactors[0] * BilinearSample( Source, CenterX, Y );
for ( int i=1; i <= KernelSize; i++ ) {
Sum += KernelFactors[i] * BilinearSample( Image, CenterX - i, Y );
Sum += KernelFactors[i] * BilinearSample( Image, CenterX + i, Y );
}
Target[X,Y] = Sum;
}
}
// Perform vertical blur
Source = Target;
Mips[MipLevel] = new float4[TargetWidth,TargetHeight];
Target = Mips[MipLevel];
for ( int X=0; X < TargetWidth; X++ ) {
for ( int Y=0; Y < TargetHeight; Y++ ) {
float CenterY = Y * MipPixelSizeY + 0.5f * (MipPixelSizeY-1);
float4 Sum = KernelFactors[0] * BilinearSample( Source, X, CenterY );
for ( int i=1; i <= KernelSize; i++ ) {
Sum += KernelFactors[i] * BilinearSample( Source, X, CenterY - i );
Sum += KernelFactors[i] * BilinearSample( Source, X, CenterY + i );
}
Target[X,Y] = Sum;
}
}
}
string Pipi = _TargetFileName.FullName;
Pipi = System.IO.Path.GetFileNameWithoutExtension( Pipi ) + ".pipi";
System.IO.FileInfo SimpleTargetFileName2 = new System.IO.FileInfo( Pipi );
using ( System.IO.FileStream S = SimpleTargetFileName2.OpenWrite() )
using ( System.IO.BinaryWriter Wr = new System.IO.BinaryWriter( S ) ) {
Wr.Write( Mips.Length );
for ( int MipLevel=0; MipLevel < Mips.Length; MipLevel++ ) {
float4[,] Mip = Mips[MipLevel];
int MipWidth = Mip.GetLength( 0 );
int MipHeight = Mip.GetLength( 1 );
Wr.Write( MipWidth );
Wr.Write( MipHeight );
for ( int Y=0; Y < MipHeight; Y++ ) {
for ( int X=0; X < MipWidth; X++ ) {
Wr.Write( Mip[X,Y].x );
Wr.Write( Mip[X,Y].y );
Wr.Write( Mip[X,Y].z );
Wr.Write( Mip[X,Y].w );
}
}
}
}
}
// //////////////////////////////////////////////////////////////////////////
// // Build "3D mips" and save as a simple format
// {
// int MaxSize = Math.Max( W, H );
// int MipsCount = (int) (Math.Ceiling( Math.Log( MaxSize+1 ) / Math.Log( 2 ) ));
//
// // 1] Build vertical mips
// float4[][,] VerticalMips = new float4[MipsCount][,];
// VerticalMips[0] = Image;
//
// int TargetHeight = H;
// for ( int MipLevel=1; MipLevel < MipsCount; MipLevel++ ) {
// int SourceHeight = TargetHeight;
//
// int BorderSize = (int) Math.Pow( 2, MipLevel-1 );
// TargetHeight = Math.Max( 1, H - 2*BorderSize );
//
// float4[,] SourceMip = VerticalMips[MipLevel-1];
// float4[,] TargetMip = new float4[W,TargetHeight];
// VerticalMips[MipLevel] = TargetMip;
// for ( int Y=0; Y < TargetHeight; Y++ ) {
// float fY = (float) (Y+0.5f) * SourceHeight / TargetHeight;
// for ( int X=0; X < W; X++ ) {
// TargetMip[X,Y] = BilinearSample( SourceMip, X, fY );
// }
// }
// }
//
//
// //MipsCount = 6;
//
// // 2] Build smoothed slices
// float4[][,] Slices = new float4[MipsCount][,];
// Slices[0] = Image;
//
// for ( int MipLevel=1; MipLevel < Slices.Length; MipLevel++ ) {
//
// int BorderSize = (int) Math.Pow( 2, MipLevel-1 ); // Each new "mip" has a border twice the size of the previous level
//
// int InsetWidth = Math.Max( 1, W - 2 * BorderSize ); // The inset image is now reduced to account for borders
// int InsetHeight = Math.Max( 1, H - 2 * BorderSize );
//
// int WidthWithBorders = W + 2 * BorderSize; // The larger image with borders that will be stored in the specific mip
// int HeightWithBorders = H + 2 * BorderSize;
//
// int Y0 = BorderSize;
// int Y1 = H - BorderSize;
//
// // Build gaussian weights
// int KernelSize = 2 * (int) BorderSize;
// float Sigma = (float) Math.Sqrt( -KernelSize*KernelSize / (2.0 * Math.Log( 0.01 )) ); // So we have a weight of 0.01 at a Kernel Size distance
// float[] KernelFactors = new float[1+KernelSize];
// float SumWeights = 0.0f;
// for ( int i=0; i <= KernelSize; i++ ) {
// KernelFactors[i] = (float) (Math.Exp( -i*i / (2.0 * Sigma * Sigma)) / Math.Sqrt( 2 * Math.PI * Sigma * Sigma ) );
// SumWeights += KernelFactors[i];
// }
//
// // Perform a horizontal blur first
// float4[,] Source = VerticalMips[MipLevel];
// float4[,] Target = new float4[W,H];
// for ( int Y=0; Y < H; Y++ ) {
// if ( Y < Y0 || Y >= Y1 ) {
// // In the borderlands
// for ( int X=0; X < W; X++ ) {
// Target[X,Y] = float4.Zero;
// }
// continue;
// }
//
// float fY = (float) (Y - Y0) * H / InsetHeight;
// for ( int X=0; X < W; X++ ) {
// float CenterX = 0.5f * W + ((float) (X+0.5f) / W - 0.5f) * WidthWithBorders;
// float4 Sum = KernelFactors[0] * BilinearSample( Source, CenterX, fY );
// for ( int i=1; i <= KernelSize; i++ ) {
// Sum += KernelFactors[i] * BilinearSample( Image, CenterX - i, fY );
// Sum += KernelFactors[i] * BilinearSample( Image, CenterX + i, fY );
// }
// Target[X,Y] = Sum;
// }
// }
//
// // Perform vertical blur
// Source = Target;
// Slices[MipLevel] = new float4[W,H];
// Target = Slices[MipLevel];
// for ( int X=0; X < W; X++ ) {
// for ( int Y=0; Y < H; Y++ ) {
// float CenterY = 0.5f * H + ((float) (Y+0.5f) / H - 0.5f) * HeightWithBorders;
// float4 Sum = KernelFactors[0] * BilinearSample( Source, X, CenterY );
// for ( int i=1; i <= KernelSize; i++ ) {
// Sum += KernelFactors[i] * BilinearSample( Source, X, CenterY - i );
// Sum += KernelFactors[i] * BilinearSample( Source, X, CenterY + i );
// }
// Target[X,Y] = Sum;
// }
// }
// }
//
//
// string Pipu = _TargetFileName.FullName;
// Pipu = System.IO.Path.GetFileNameWithoutExtension( Pipu ) + ".pipu";
// System.IO.FileInfo SimpleTargetFileName2 = new System.IO.FileInfo( Pipu );
// using ( System.IO.FileStream S = SimpleTargetFileName2.OpenWrite() )
// using ( System.IO.BinaryWriter Wr = new System.IO.BinaryWriter( S ) ) {
// Wr.Write( Slices.Length );
// Wr.Write( W );
// Wr.Write( H );
//
// for ( int MipLevel=0; MipLevel < Slices.Length; MipLevel++ ) {
// float4[,] Mip = Slices[MipLevel];
// for ( int Y=0; Y < H; Y++ ) {
// for ( int X=0; X < W; X++ ) {
// Wr.Write( Mip[X,Y].x );
// Wr.Write( Mip[X,Y].y );
// Wr.Write( Mip[X,Y].z );
// Wr.Write( Mip[X,Y].w );
// }
// }
// }
// }
// }
//////////////////////////////////////////////////////////////////////////
// Build the SAT
for ( int Y=0; Y < H; Y++ ) {
for ( int X=1; X < W; X++ ) {
Image[X,Y] += Image[X-1,Y]; // Accumulate along X
}
}
for ( int X=0; X < W; X++ ) {
for ( int Y=1; Y < H; Y++ ) {
Image[X,Y] += Image[X,Y-1]; // Accumulate along Y
}
}
// DirectXTexManaged.TextureCreator.CreateRGBA16FFile( _TargetFileName.FullName, Image );
throw new Exception( "Deprecated!" );
// Save as a simple format
string Pipo = _TargetFileName.FullName;
Pipo = System.IO.Path.GetFileNameWithoutExtension( Pipo ) + ".pipo";
System.IO.FileInfo SimpleTargetFileName = new System.IO.FileInfo( Pipo );
using ( System.IO.FileStream S = SimpleTargetFileName.OpenWrite() )
using ( System.IO.BinaryWriter Wr = new System.IO.BinaryWriter( S ) ) {
Wr.Write( W );
Wr.Write( H );
for ( int Y=0; Y < H; Y++ ) {
for ( int X=0; X < W; X++ ) {
Wr.Write( Image[X,Y].x );
Wr.Write( Image[X,Y].y );
Wr.Write( Image[X,Y].z );
Wr.Write( Image[X,Y].w );
}
}
}
}