mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Some texfile formatting.
This commit is contained in:
parent
a95877b9e4
commit
2da6a33a62
1 changed files with 63 additions and 80 deletions
|
|
@ -8,36 +8,30 @@ namespace Penumbra.Import.Textures;
|
||||||
|
|
||||||
public static class TexFileParser
|
public static class TexFileParser
|
||||||
{
|
{
|
||||||
public static ScratchImage Parse( Stream data )
|
public static ScratchImage Parse(Stream data)
|
||||||
{
|
{
|
||||||
using var r = new BinaryReader( data );
|
using var r = new BinaryReader(data);
|
||||||
var header = r.ReadStructure< TexFile.TexHeader >();
|
var header = r.ReadStructure<TexFile.TexHeader>();
|
||||||
|
|
||||||
var meta = header.ToTexMeta();
|
var meta = header.ToTexMeta();
|
||||||
if( meta.Format == DXGIFormat.Unknown )
|
if (meta.Format == DXGIFormat.Unknown)
|
||||||
{
|
throw new Exception($"Could not convert format {header.Format} to DXGI Format.");
|
||||||
throw new Exception( $"Could not convert format {header.Format} to DXGI Format." );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( meta.Dimension == TexDimension.Unknown )
|
if (meta.Dimension == TexDimension.Unknown)
|
||||||
{
|
throw new Exception($"Could not obtain dimensionality from {header.Type}.");
|
||||||
throw new Exception( $"Could not obtain dimensionality from {header.Type}." );
|
|
||||||
}
|
|
||||||
|
|
||||||
meta.MipLevels = CountMipLevels( data, in meta, in header );
|
meta.MipLevels = CountMipLevels(data, in meta, in header);
|
||||||
if( meta.MipLevels == 0 )
|
if (meta.MipLevels == 0)
|
||||||
{
|
throw new Exception("Could not load file. Image is corrupted and does not contain enough data for its size.");
|
||||||
throw new Exception( "Could not load file. Image is corrupted and does not contain enough data for its size." );
|
|
||||||
}
|
|
||||||
|
|
||||||
var scratch = ScratchImage.Initialize( meta );
|
var scratch = ScratchImage.Initialize(meta);
|
||||||
|
|
||||||
CopyData( scratch, r );
|
CopyData(scratch, r);
|
||||||
|
|
||||||
return scratch;
|
return scratch;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe int CountMipLevels( Stream data, in TexMeta meta, in TexFile.TexHeader header )
|
private static unsafe int CountMipLevels(Stream data, in TexMeta meta, in TexFile.TexHeader header)
|
||||||
{
|
{
|
||||||
var width = meta.Width;
|
var width = meta.Width;
|
||||||
var height = meta.Height;
|
var height = meta.Height;
|
||||||
|
|
@ -46,28 +40,22 @@ public static class TexFileParser
|
||||||
var lastOffset = 0L;
|
var lastOffset = 0L;
|
||||||
var lastSize = 80L;
|
var lastSize = 80L;
|
||||||
var minSize = meta.Format.IsCompressed() ? 4 : 1;
|
var minSize = meta.Format.IsCompressed() ? 4 : 1;
|
||||||
for( var i = 0; i < 13; ++i )
|
for (var i = 0; i < 13; ++i)
|
||||||
{
|
{
|
||||||
var offset = header.OffsetToSurface[ i ];
|
var offset = header.OffsetToSurface[i];
|
||||||
if( offset == 0 )
|
if (offset == 0)
|
||||||
{
|
|
||||||
return i;
|
return i;
|
||||||
}
|
|
||||||
|
|
||||||
var requiredSize = width * height * bits / 8;
|
var requiredSize = width * height * bits / 8;
|
||||||
if( offset + requiredSize > data.Length )
|
if (offset + requiredSize > data.Length)
|
||||||
{
|
|
||||||
return i;
|
return i;
|
||||||
}
|
|
||||||
|
|
||||||
var diff = offset - lastOffset;
|
var diff = offset - lastOffset;
|
||||||
if( diff != lastSize )
|
if (diff != lastSize)
|
||||||
{
|
|
||||||
return i;
|
return i;
|
||||||
}
|
|
||||||
|
|
||||||
width = Math.Max( width / 2, minSize );
|
width = Math.Max(width / 2, minSize);
|
||||||
height = Math.Max( height / 2, minSize );
|
height = Math.Max(height / 2, minSize);
|
||||||
lastOffset = offset;
|
lastOffset = offset;
|
||||||
lastSize = requiredSize;
|
lastSize = requiredSize;
|
||||||
}
|
}
|
||||||
|
|
@ -75,48 +63,45 @@ public static class TexFileParser
|
||||||
return 13;
|
return 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe void CopyData( ScratchImage image, BinaryReader r )
|
private static unsafe void CopyData(ScratchImage image, BinaryReader r)
|
||||||
{
|
{
|
||||||
fixed( byte* ptr = image.Pixels )
|
fixed (byte* ptr = image.Pixels)
|
||||||
{
|
{
|
||||||
var span = new Span< byte >( ptr, image.Pixels.Length );
|
var span = new Span<byte>(ptr, image.Pixels.Length);
|
||||||
var readBytes = r.Read( span );
|
var readBytes = r.Read(span);
|
||||||
if( readBytes < image.Pixels.Length )
|
if (readBytes < image.Pixels.Length)
|
||||||
{
|
throw new Exception($"Invalid data length {readBytes} < {image.Pixels.Length}.");
|
||||||
throw new Exception( $"Invalid data length {readBytes} < {image.Pixels.Length}." );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Write( this TexFile.TexHeader header, BinaryWriter w )
|
public static void Write(this TexFile.TexHeader header, BinaryWriter w)
|
||||||
{
|
{
|
||||||
w.Write( ( uint )header.Type );
|
w.Write((uint)header.Type);
|
||||||
w.Write( ( uint )header.Format );
|
w.Write((uint)header.Format);
|
||||||
w.Write( header.Width );
|
w.Write(header.Width);
|
||||||
w.Write( header.Height );
|
w.Write(header.Height);
|
||||||
w.Write( header.Depth );
|
w.Write(header.Depth);
|
||||||
w.Write( header.MipLevels );
|
w.Write((byte) header.MipLevels);
|
||||||
|
w.Write((byte) 0); // TODO Lumina Update
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
w.Write( header.LodOffset[ 0 ] );
|
w.Write(header.LodOffset[0]);
|
||||||
w.Write( header.LodOffset[ 1 ] );
|
w.Write(header.LodOffset[1]);
|
||||||
w.Write( header.LodOffset[ 2 ] );
|
w.Write(header.LodOffset[2]);
|
||||||
for( var i = 0; i < 13; ++i )
|
for (var i = 0; i < 13; ++i)
|
||||||
{
|
w.Write(header.OffsetToSurface[i]);
|
||||||
w.Write( header.OffsetToSurface[ i ] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TexFile.TexHeader ToTexHeader( this ScratchImage scratch )
|
public static TexFile.TexHeader ToTexHeader(this ScratchImage scratch)
|
||||||
{
|
{
|
||||||
var meta = scratch.Meta;
|
var meta = scratch.Meta;
|
||||||
var ret = new TexFile.TexHeader()
|
var ret = new TexFile.TexHeader()
|
||||||
{
|
{
|
||||||
Height = ( ushort )meta.Height,
|
Height = (ushort)meta.Height,
|
||||||
Width = ( ushort )meta.Width,
|
Width = (ushort)meta.Width,
|
||||||
Depth = ( ushort )Math.Max( meta.Depth, 1 ),
|
Depth = (ushort)Math.Max(meta.Depth, 1),
|
||||||
MipLevels = ( ushort )Math.Min( meta.MipLevels, 12 ),
|
MipLevels = (byte)Math.Min(meta.MipLevels, 12),
|
||||||
Format = meta.Format.ToTexFormat(),
|
Format = meta.Format.ToTexFormat(),
|
||||||
Type = meta.Dimension switch
|
Type = meta.Dimension switch
|
||||||
{
|
{
|
||||||
|
|
@ -128,50 +113,48 @@ public static class TexFileParser
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
ret.FillSurfaceOffsets( scratch );
|
ret.FillSurfaceOffsets(scratch);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe void FillSurfaceOffsets( this ref TexFile.TexHeader header, ScratchImage scratch )
|
private static unsafe void FillSurfaceOffsets(this ref TexFile.TexHeader header, ScratchImage scratch)
|
||||||
{
|
{
|
||||||
var idx = 0;
|
var idx = 0;
|
||||||
fixed( byte* ptr = scratch.Pixels )
|
fixed (byte* ptr = scratch.Pixels)
|
||||||
{
|
{
|
||||||
foreach( var image in scratch.Images )
|
foreach (var image in scratch.Images)
|
||||||
{
|
{
|
||||||
var offset = ( byte* )image.Pixels - ptr;
|
var offset = (byte*)image.Pixels - ptr;
|
||||||
header.OffsetToSurface[ idx++ ] = ( uint )( 80 + offset );
|
header.OffsetToSurface[idx++] = (uint)(80 + offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for( ; idx < 13; ++idx )
|
for (; idx < 13; ++idx)
|
||||||
{
|
header.OffsetToSurface[idx] = 0;
|
||||||
header.OffsetToSurface[ idx ] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
header.LodOffset[ 0 ] = 0;
|
header.LodOffset[0] = 0;
|
||||||
header.LodOffset[ 1 ] = 1;
|
header.LodOffset[1] = 1;
|
||||||
header.LodOffset[ 2 ] = 2;
|
header.LodOffset[2] = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static TexMeta ToTexMeta( this TexFile.TexHeader header )
|
public static TexMeta ToTexMeta(this TexFile.TexHeader header)
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
Height = header.Height,
|
Height = header.Height,
|
||||||
Width = header.Width,
|
Width = header.Width,
|
||||||
Depth = Math.Max( header.Depth, ( ushort )1 ),
|
Depth = Math.Max(header.Depth, (ushort)1),
|
||||||
MipLevels = header.MipLevels,
|
MipLevels = header.MipLevels,
|
||||||
ArraySize = 1,
|
ArraySize = 1,
|
||||||
Format = header.Format.ToDXGI(),
|
Format = header.Format.ToDXGI(),
|
||||||
Dimension = header.Type.ToDimension(),
|
Dimension = header.Type.ToDimension(),
|
||||||
MiscFlags = header.Type.HasFlag( TexFile.Attribute.TextureTypeCube ) ? D3DResourceMiscFlags.TextureCube : 0,
|
MiscFlags = header.Type.HasFlag(TexFile.Attribute.TextureTypeCube) ? D3DResourceMiscFlags.TextureCube : 0,
|
||||||
MiscFlags2 = 0,
|
MiscFlags2 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static TexDimension ToDimension( this TexFile.Attribute attribute )
|
private static TexDimension ToDimension(this TexFile.Attribute attribute)
|
||||||
=> ( attribute & TexFile.Attribute.TextureTypeMask ) switch
|
=> (attribute & TexFile.Attribute.TextureTypeMask) switch
|
||||||
{
|
{
|
||||||
TexFile.Attribute.TextureType1D => TexDimension.Tex1D,
|
TexFile.Attribute.TextureType1D => TexDimension.Tex1D,
|
||||||
TexFile.Attribute.TextureType2D => TexDimension.Tex2D,
|
TexFile.Attribute.TextureType2D => TexDimension.Tex2D,
|
||||||
|
|
@ -179,7 +162,7 @@ public static class TexFileParser
|
||||||
_ => TexDimension.Unknown,
|
_ => TexDimension.Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static TexFile.TextureFormat ToTexFormat( this DXGIFormat format )
|
public static TexFile.TextureFormat ToTexFormat(this DXGIFormat format)
|
||||||
=> format switch
|
=> format switch
|
||||||
{
|
{
|
||||||
DXGIFormat.R8UNorm => TexFile.TextureFormat.L8,
|
DXGIFormat.R8UNorm => TexFile.TextureFormat.L8,
|
||||||
|
|
@ -204,7 +187,7 @@ public static class TexFileParser
|
||||||
_ => TexFile.TextureFormat.Unknown,
|
_ => TexFile.TextureFormat.Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static DXGIFormat ToDXGI( this TexFile.TextureFormat format )
|
public static DXGIFormat ToDXGI(this TexFile.TextureFormat format)
|
||||||
=> format switch
|
=> format switch
|
||||||
{
|
{
|
||||||
TexFile.TextureFormat.L8 => DXGIFormat.R8UNorm,
|
TexFile.TextureFormat.L8 => DXGIFormat.R8UNorm,
|
||||||
|
|
@ -229,4 +212,4 @@ public static class TexFileParser
|
||||||
TexFile.TextureFormat.Shadow24 => DXGIFormat.R24G8Typeless,
|
TexFile.TextureFormat.Shadow24 => DXGIFormat.R24G8Typeless,
|
||||||
_ => DXGIFormat.Unknown,
|
_ => DXGIFormat.Unknown,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue