Skip to content

Commit b68ce8e

Browse files
committed
Changed around some of the Properties on ImageFormatDetails to allow DX10 Header to be included.
1 parent e73d343 commit b68ce8e

5 files changed

Lines changed: 91 additions & 49 deletions

File tree

CSharpImageLibrary/DDS/DDSGeneral.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ internal static List<MipMap> LoadDDS(MemoryStream compressed, DDS_Header header,
9797
ImageEngineFormat format = header.Format;
9898

9999
int estimatedMips = header.dwMipMapCount;
100-
int mipOffset = formatDetails.Format == ImageEngineFormat.DDS_DX10 ? 148 : 128; // Includes header.
100+
int mipOffset = formatDetails.HeaderSize;
101101
int originalOffset = mipOffset;
102102

103103
if (!EnsureMipInImage(compressed.Length, mipWidth, mipHeight, 4, formatDetails, out mipOffset)) // Update number of mips too
@@ -108,7 +108,7 @@ internal static List<MipMap> LoadDDS(MemoryStream compressed, DDS_Header header,
108108

109109
mipOffset = originalOffset; // Needs resetting after checking there's mips in this image.
110110

111-
// TESTUNIG
111+
// Ensure there's at least 1 mipmap
112112
if (estimatedMips == 0)
113113
estimatedMips = 1;
114114

@@ -121,7 +121,7 @@ internal static List<MipMap> LoadDDS(MemoryStream compressed, DDS_Header header,
121121
throw new InvalidDataException($"Requested mipmap does not exist in this image. Top Image Size: {mipWidth}x{mipHeight}, requested mip max dimension: {desiredMaxDimension}.");
122122

123123
// Not the first mipmap.
124-
if (mipOffset > 128)
124+
if (mipOffset > formatDetails.HeaderSize)
125125
{
126126

127127
double divisor = mipHeight > mipWidth ? mipHeight / desiredMaxDimension : mipWidth / desiredMaxDimension;
@@ -132,7 +132,7 @@ internal static List<MipMap> LoadDDS(MemoryStream compressed, DDS_Header header,
132132
{
133133
mipHeight = header.Height;
134134
mipWidth = header.Width;
135-
mipOffset = 128;
135+
mipOffset = formatDetails.HeaderSize;
136136
}
137137
else
138138
{
@@ -141,7 +141,7 @@ internal static List<MipMap> LoadDDS(MemoryStream compressed, DDS_Header header,
141141
}
142142
}
143143
else // The first mipmap
144-
mipOffset = 128;
144+
mipOffset = formatDetails.HeaderSize;
145145

146146
}
147147

@@ -243,7 +243,7 @@ internal static byte[] Save(List<MipMap> mipMaps, ImageFormats.ImageEngineFormat
243243
// Create header and write to destination
244244
DDS_Header header = new DDS_Header(mipMaps.Count, height, width, destFormatDetails.Format);
245245

246-
int headerLength = destFormatDetails.Format == ImageEngineFormat.DDS_DX10 ? 148 : 128;
246+
int headerLength = destFormatDetails.HeaderSize;
247247

248248
int fullSize = GetCompressedSizeOfImage(mipMaps.Count, destFormatDetails, width, height);
249249
if (destFormatDetails.ComponentSize != 1)
@@ -403,17 +403,16 @@ public static bool EnsureMipInImage(long streamLength, int mainWidth, int mainHe
403403
{
404404
if (mainWidth <= desiredMipDimension && mainHeight <= desiredMipDimension)
405405
{
406-
mipOffset = 128;
406+
mipOffset = destFormatDetails.HeaderSize;
407407
return true; // One mip only
408-
// TODO: DX10
409408
}
410409

411410
int dependentDimension = mainWidth > mainHeight ? mainWidth : mainHeight;
412411
int mipIndex = (int)Math.Log((dependentDimension / desiredMipDimension), 2);
413412
if (mipIndex < -1)
414413
throw new InvalidDataException($"Invalid dimensions for mipmapping. Got desired: {desiredMipDimension} and dependent: {dependentDimension}");
415414

416-
int requiredOffset = GetMipOffset(mipIndex, destFormatDetails, mainHeight, mainWidth); // +128 for header
415+
int requiredOffset = GetMipOffset(mipIndex, destFormatDetails, mainHeight, mainWidth);
417416

418417
// KFreon: Something wrong with the count here by 1 i.e. the estimate is 1 more than it should be
419418
if (destFormatDetails.Format == ImageEngineFormat.DDS_ARGB_8) // TODO: Might not just be 8 bit, still don't know why it's wrong.
@@ -422,7 +421,7 @@ public static bool EnsureMipInImage(long streamLength, int mainWidth, int mainHe
422421
mipOffset = requiredOffset;
423422

424423
// Should only occur when an image has 0 or 1 mipmap.
425-
if (streamLength <= (requiredOffset - 128))
424+
if (streamLength <= (requiredOffset - destFormatDetails.HeaderSize))
426425
return false;
427426

428427
return true;
@@ -473,7 +472,7 @@ divWidth and divHeight are the block compress adjusted dimensions (uncompressed
473472
double sumPart = mipIndex == -1 ? 0 :
474473
(1d / 3d) * (4d - shift); // Shifting represents 4^-mipIndex. Math.Pow seems slow.
475474

476-
double totalSize = 128 + (sumPart * destFormatDetails.BlockSize * (baseWidth / divisor) * (baseHeight / divisor));
475+
double totalSize = destFormatDetails.HeaderSize + (sumPart * destFormatDetails.BlockSize * (baseWidth / divisor) * (baseHeight / divisor));
477476
if (requiresTinyAdjustment)
478477
totalSize += destFormatDetails.BlockSize * 2;
479478

CSharpImageLibrary/Headers/DDS_Header.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace CSharpImageLibrary.Headers
1515
/// </summary>
1616
public class DDS_Header : AbstractHeader
1717
{
18-
const int HeaderSize = 152;
18+
const int MaxHeaderSize = ImageFormats.DDS_DX10_HEADER_LENGTH;
1919

2020
/// <summary>
2121
/// Characters beginning a file that indicate file is a DDS image.
@@ -829,7 +829,7 @@ string DDS_FlagStringify(Type enumType)
829829
protected override long Load(Stream stream)
830830
{
831831
base.Load(stream);
832-
var temp = stream.ReadBytes(HeaderSize);
832+
var temp = stream.ReadBytes(MaxHeaderSize);
833833

834834
if (!CheckIdentifier(temp))
835835
throw new FormatException("Stream is not a recognised DDS image.");
@@ -858,7 +858,7 @@ protected override long Load(Stream stream)
858858
if (ddspf.dwFourCC == FourCC.DX10)
859859
DX10_DXGI_AdditionalHeader = new DDS_DXGI_DX10_Additional(temp);
860860

861-
return HeaderSize;
861+
return MaxHeaderSize;
862862
}
863863

864864
/// <summary>

CSharpImageLibrary/ImageEngineFormatDetails.cs

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,69 +9,89 @@ namespace CSharpImageLibrary
99
{
1010
public partial class ImageFormats
1111
{
12+
/// <summary>
13+
/// Length of header in bytes when Additional DX10 Header is present.
14+
/// </summary>
15+
public const int DDS_DX10_HEADER_LENGTH = 148;
16+
17+
18+
/// <summary>
19+
/// Length of header when pre-DX10 format.
20+
/// </summary>
21+
public const int DDS_NO_DX10_HEADER_LENGTH = 128;
22+
23+
24+
1225
/// <summary>
1326
/// Detailed representation of an image format.
1427
/// </summary>
1528
[DebuggerDisplay("Format: {Format}, ComponentSize: {ComponentSize}")]
1629
public class ImageEngineFormatDetails
1730
{
31+
/// <summary>
32+
/// Length of header (DDS only)
33+
/// </summary>
34+
public int HeaderSize => Format == ImageEngineFormat.DDS_DX10 ? DDS_DX10_HEADER_LENGTH : DDS_NO_DX10_HEADER_LENGTH;
35+
36+
1837
/// <summary>
1938
/// Format of details.
2039
/// </summary>
21-
public ImageEngineFormat Format;
40+
public ImageEngineFormat Format { get; }
2241

2342
/// <summary>
2443
/// Indicates whether format contains premultiplied alpha.
2544
/// </summary>
26-
public bool IsPremultipliedFormat;
45+
public bool IsPremultipliedFormat => Format == ImageEngineFormat.DDS_DXT2 || Format == ImageEngineFormat.DDS_DXT4;
2746

2847
/// <summary>
2948
/// Number of bytes in colour.
3049
/// </summary>
31-
public int ComponentSize;
50+
public int ComponentSize => (BitCount / 8) / MaxNumberOfChannels;
3251

3352
/// <summary>
3453
/// Number of bits in colour.
3554
/// </summary>
36-
public int BitCount;
55+
public int BitCount { get; }
3756

3857
/// <summary>
3958
/// Indicates whether supported format is Block Compressed.
4059
/// </summary>
41-
public bool IsBlockCompressed;
60+
public bool IsBlockCompressed => IsBlockCompressed(Format);
4261

4362
/// <summary>
4463
/// Indicates whether format supports mipmaps.
4564
/// </summary>
46-
public bool IsMippable;
65+
public bool IsMippable => IsFormatMippable(Format);
4766

4867
/// <summary>
4968
/// Size of a discrete block in bytes. (e.g. 2 channel 8 bit colour = 2, DXT1 = 16). Block can mean texel (DXTn) or pixel (uncompressed)
5069
/// </summary>
51-
public int BlockSize;
70+
public int BlockSize => GetBlockSize(Format, ComponentSize);
5271

5372
/// <summary>
5473
/// String representation of formats' file extension. No '.'.
5574
/// </summary>
56-
public string Extension;
75+
public string Extension => Supported_Extension.ToString();
5776

5877
/// <summary>
5978
/// Enum version of formats' file extension.
6079
/// </summary>
61-
public SupportedExtensions Supported_Extension;
80+
public SupportedExtensions Supported_Extension => IsDDS ? SupportedExtensions.DDS : ParseExtension(Format.ToString());
6281

6382
/// <summary>
6483
/// Indicates whether format is a DDS format.
6584
/// </summary>
66-
public bool IsDDS;
85+
public bool IsDDS => Format.ToString().Contains("DDS") || Format == ImageEngineFormat.DDS_DX10;
6786

6887
/// <summary>
6988
/// Max number of supported channels. Usually 4, but some formats are 1 (G8), 2 (V8U8), or 3 (RGB) channels.
7089
/// </summary>
71-
public int MaxNumberOfChannels;
90+
public int MaxNumberOfChannels => MaxNumberOfChannels(Format);
7291

7392
/// <summary>
7493
/// Writes the max value to array using the correct bit styles.
94+
/// e.g. Will write int.Max when component size is int.Length (4 bytes).
7595
/// </summary>
7696
public Action<byte[], int> SetMaxValue = null;
7797

@@ -93,7 +113,14 @@ public class ImageEngineFormatDetails
93113
Func<byte[], int, byte[]> ReadUShortAsArray = null;
94114
Func<byte[], int, byte[]> ReadFloatAsArray = null;
95115

116+
/// <summary>
117+
/// Holds the encoder to be used when compressing/writing image.
118+
/// </summary>
96119
public Action<byte[], int, int, byte[], int, AlphaSettings, ImageEngineFormatDetails> BlockEncoder = null;
120+
121+
/// <summary>
122+
/// Holds the decoder to be used when decompressing/reading image.
123+
/// </summary>
97124
public Action<byte[], int, byte[], int, int, bool> BlockDecoder = null;
98125

99126
/// <summary>
@@ -109,13 +136,7 @@ public class ImageEngineFormatDetails
109136
public ImageEngineFormatDetails(ImageEngineFormat inFormat, Headers.DDS_Header.DXGI_FORMAT DX10Format = new Headers.DDS_Header.DXGI_FORMAT())
110137
{
111138
Format = inFormat;
112-
IsPremultipliedFormat = inFormat == ImageEngineFormat.DDS_DXT2 || inFormat == ImageEngineFormat.DDS_DXT4;
113-
IsDDS = inFormat.ToString().Contains("DDS") || inFormat == ImageEngineFormat.DDS_DX10;
114-
MaxNumberOfChannels = MaxNumberOfChannels(inFormat);
115-
116-
Supported_Extension = IsDDS ? SupportedExtensions.DDS : ParseExtension(inFormat.ToString());
117-
Extension = Supported_Extension.ToString();
118-
139+
119140
BitCount = 8;
120141
{
121142
switch (inFormat)
@@ -161,11 +182,6 @@ public class ImageEngineFormatDetails
161182
}
162183
}
163184

164-
ComponentSize = (BitCount / 8) / MaxNumberOfChannels;
165-
BlockSize = GetBlockSize(inFormat, ComponentSize);
166-
IsBlockCompressed = IsBlockCompressed(inFormat);
167-
IsMippable = IsFormatMippable(inFormat);
168-
169185
// Functions
170186
ReadByte = ReadByteFromByte;
171187
ReadUShort = ReadUShortFromByte;
@@ -206,7 +222,10 @@ public class ImageEngineFormatDetails
206222
BlockEncoder = DDS_Encoders.CompressBC5Block;
207223
break;
208224
case ImageEngineFormat.DDS_DX10:
209-
BlockEncoder = DDS_Encoders.CompressBC7Block;
225+
if (DX10Format.ToString().Contains("BC7"))
226+
BlockEncoder = DDS_Encoders.CompressBC7Block;
227+
else
228+
BlockEncoder = DDS_Encoders.CompressBC6Block;
210229
break;
211230
case ImageEngineFormat.DDS_DXT1:
212231
BlockEncoder = DDS_Encoders.CompressBC1Block;

CSharpImageLibrary/ImageEngineImage.cs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,35 @@ public int NumberOfChannels
114114
}
115115
}
116116

117-
public int BitCount { get { return FormatDetails.BitCount; } }
118-
public int ComponentSize { get { return FormatDetails.ComponentSize; } }
119-
public bool IsBlockCompressed { get { return FormatDetails.IsBlockCompressed; } }
120-
public int BlockSize { get { return FormatDetails.BlockSize; } }
121-
public bool IsMippable { get { return FormatDetails.IsMippable; } }
122-
public string FileExtension { get { return FormatDetails.Extension; } }
117+
/// <summary>
118+
/// Number of bits per colour.
119+
/// </summary>
120+
public int BitCount => FormatDetails.BitCount;
121+
122+
/// <summary>
123+
/// Number of bytes per colour. i.e. 1 byte, 4 bytes (int), etc
124+
/// </summary>
125+
public int ComponentSize => FormatDetails.ComponentSize;
126+
127+
/// <summary>
128+
/// True = Image is a block compressed DDS.
129+
/// </summary>
130+
public bool IsBlockCompressed => FormatDetails.IsBlockCompressed;
131+
132+
/// <summary>
133+
/// Size of compressed blocks. Affected by component size. Default is 1 for normal images (jpg, etc)
134+
/// </summary>
135+
public int BlockSize => FormatDetails.BlockSize;
136+
137+
/// <summary>
138+
/// True = Format is able to contain mipmaps.
139+
/// </summary>
140+
public bool IsMippable => FormatDetails.IsMippable;
141+
142+
/// <summary>
143+
/// File Extension of selected format.
144+
/// </summary>
145+
public string FileExtension => FormatDetails.Extension;
123146
#endregion Properties
124147

125148
/// <summary>
@@ -275,8 +298,8 @@ byte[] AttemptSaveUsingOriginalData(ImageFormats.ImageEngineFormatDetails destFo
275298

276299
if (destFormatDetails.IsDDS)
277300
{
278-
destStart = destFormatDetails.Format == ImageEngineFormat.DDS_DX10 ? 148 : 128;
279-
start = destFormatDetails.Format == ImageEngineFormat.DDS_DX10 ? 148 : 128;
301+
destStart = destFormatDetails.HeaderSize;
302+
start = destStart;
280303

281304
int mipCount = 0;
282305

@@ -416,7 +439,7 @@ byte[] AttemptSaveUsingOriginalData(ImageFormats.ImageEngineFormatDetails destFo
416439
data = new byte[formattedMips.Length + length];
417440

418441
// Copy smaller mips to destination
419-
Array.Copy(formattedMips, 128, data, length, formattedMips.Length - 128);
442+
Array.Copy(formattedMips, destFormatDetails.HeaderSize, data, length, formattedMips.Length - destFormatDetails.HeaderSize);
420443
break;
421444
case MipHandling.KeepTopOnly:
422445
mipCount = 1;

UI_Project/NewViewModel.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,9 +1223,10 @@ internal async Task<bool> LoadImage(byte[] data)
12231223
// Full image
12241224
try
12251225
{
1226-
LoadedImage = await Task.Run(() => new ImageEngineImage(data));
1226+
//LoadedImage = await Task.Run(() => new ImageEngineImage(data));
1227+
LoadedImage = await Task.Run(() => new ImageEngineImage(data, 1024));
12271228
}
1228-
catch(Exception e)
1229+
catch (Exception e)
12291230
{
12301231
LoadFailError = e.Message;
12311232
LoadFailed = true;

0 commit comments

Comments
 (0)