2 Vampyre Imaging Library
4 http://imaginglib.sourceforge.net
6 The contents of this file are used with permission, subject to the Mozilla
7 Public License Version 1.1 (the "License"); you may not use this file except
8 in compliance with the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/MPL-1.1.html
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
13 the specific language governing rights and limitations under the License.
15 Alternatively, the contents of this file may be used under the terms of the
16 GNU Lesser General Public License (the "LGPL License"), in which case the
17 provisions of the LGPL License are applicable instead of those above.
18 If you wish to allow use of your version of this file only under the terms
19 of the LGPL License and not to allow others to use your version of this file
20 under the MPL, indicate your decision by deleting the provisions above and
21 replace them with the notice and other provisions required by the LGPL
22 License. If you do not delete the provisions above, a recipient may use
23 your version of this file under either the MPL or the LGPL License.
25 For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
28 { This unit contains image format loader/saver for DirectDraw Surface images.}
31 {$I ImagingOptions.inc}
36 ImagingTypes
, Imaging
, ImagingUtility
, ImagingFormats
;
39 { Class for loading and saving Microsoft DirectDraw surfaces.
40 It can load/save all D3D formats which have coresponding
41 TImageFormat. It supports plain textures, cube textures and
42 volume textures, all of these can have mipmaps. It can also
43 load some formats which have no exact TImageFormat, but can be easily
44 converted to one (bump map formats, etc.).
45 You can get some information about last loaded DDS file by calling
46 GetOption with ImagingDDSLoadedXXX options and you can set some
47 saving options by calling SetOption with ImagingDDSSaveXXX or you can
48 simply use properties of this class.
49 Note that when saving cube maps and volumes input image array must contain
50 at least number of images to build cube/volume based on current
51 Depth and MipMapCount settings.}
52 TDDSFileFormat
= class(TImageFileFormat
)
54 FLoadedCubeMap
: LongBool;
55 FLoadedVolume
: LongBool;
56 FLoadedMipMapCount
: LongInt;
57 FLoadedDepth
: LongInt;
58 FSaveCubeMap
: LongBool;
59 FSaveVolume
: LongBool;
60 FSaveMipMapCount
: LongInt;
62 procedure ComputeSubDimensions(Idx
, Width
, Height
, MipMaps
, Depth
: LongInt;
63 IsCubeMap
, IsVolume
: Boolean; var CurWidth
, CurHeight
: LongInt);
65 procedure Define
; override;
66 function LoadData(Handle
: TImagingHandle
; var Images
: TDynImageDataArray
;
67 OnlyFirstLevel
: Boolean): Boolean; override;
68 function SaveData(Handle
: TImagingHandle
; const Images
: TDynImageDataArray
;
69 Index
: LongInt): Boolean; override;
70 procedure ConvertToSupported(var Image
: TImageData
;
71 const Info
: TImageFormatInfo
); override;
73 function TestFormat(Handle
: TImagingHandle
): Boolean; override;
74 procedure CheckOptionsValidity
; override;
76 { True if last loaded DDS file was cube map.}
77 property LoadedCubeMap
: LongBool read FLoadedCubeMap write FLoadedCubeMap
;
78 { True if last loaded DDS file was volume texture.}
79 property LoadedVolume
: LongBool read FLoadedVolume write FLoadedVolume
;
80 { Number of mipmap levels of last loaded DDS image.}
81 property LoadedMipMapCount
: LongInt read FLoadedMipMapCount write FLoadedMipMapCount
;
82 { Depth (slices of volume texture or faces of cube map) of last loaded DDS image.}
83 property LoadedDepth
: LongInt read FLoadedDepth write FLoadedDepth
;
84 { True if next DDS file to be saved should be stored as cube map.}
85 property SaveCubeMap
: LongBool read FSaveCubeMap write FSaveCubeMap
;
86 { True if next DDS file to be saved should be stored as volume texture.}
87 property SaveVolume
: LongBool read FSaveVolume write FSaveVolume
;
88 { Sets the number of mipmaps which should be stored in the next saved DDS file.
89 Only applies to cube maps and volumes, ordinary 2D textures save all
90 levels present in input.}
91 property SaveMipMapCount
: LongInt read FSaveMipMapCount write FSaveMipMapCount
;
92 { Sets the depth (slices of volume texture or faces of cube map)
93 of the next saved DDS file.}
94 property SaveDepth
: LongInt read FSaveDepth write FSaveDepth
;
98 { DDS related metadata Ids }
100 { DXGI format of textures stored in DDS files with DX10 extension. Type is
101 Enum (value corresponding to DXGI_FORMAT enum from DX SDK).}
102 SMetaDdsDxgiFormat
= 'DdsDxgiFormat';
103 { Number of mipmaps for each main image in DDS file.}
104 SMetaDdsMipMapCount
= 'DdsMipMapCount';
105 { Texture array size stored in DDS file (DX10 extension).}
106 SMetaDdsArraySize
= 'DdsArraySize';
111 SDDSFormatName
= 'DirectDraw Surface';
113 DDSSupportedFormats
: TImageFormats
= [ifR8G8B8
, ifA8R8G8B8
, ifX8R8G8B8
,
114 ifA1R5G5B5
, ifA4R4G4B4
, ifX1R5G5B5
, ifX4R4G4B4
, ifR5G6B5
, ifA16B16G16R16
,
115 ifR32F
, ifA32B32G32R32F
, ifR16F
, ifA16B16G16R16F
, ifR3G3B2
, ifGray8
, ifA8Gray8
,
116 ifGray16
, ifDXT1
, ifDXT3
, ifDXT5
, ifATI1N
, ifATI2N
];
119 { Four character codes.}
120 DDSMagic
= LongWord(Byte('D') or (Byte('D') shl 8) or (Byte('S') shl 16) or
122 FOURCC_DXT1
= LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or
124 FOURCC_DXT3
= LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or
126 FOURCC_DXT5
= LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or
128 FOURCC_ATI1
= LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or
130 FOURCC_ATI2
= LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or
132 FOURCC_DX10
= LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('1') shl 16) or
135 { Some D3DFORMAT values used in DDS files as FourCC value.}
136 D3DFMT_A16B16G16R16
= 36;
138 D3DFMT_A32B32G32R32F
= 116;
140 D3DFMT_A16B16G16R16F
= 113;
142 { Constans used by TDDSurfaceDesc2.Flags.}
143 DDSD_CAPS
= $00000001;
144 DDSD_HEIGHT
= $00000002;
145 DDSD_WIDTH
= $00000004;
146 DDSD_PITCH
= $00000008;
147 DDSD_PIXELFORMAT
= $00001000;
148 DDSD_MIPMAPCOUNT
= $00020000;
149 DDSD_LINEARSIZE
= $00080000;
150 DDSD_DEPTH
= $00800000;
152 { Constans used by TDDSPixelFormat.Flags.}
153 DDPF_ALPHAPIXELS
= $00000001; // used by formats which contain alpha
154 DDPF_FOURCC
= $00000004; // used by DXT and large ARGB formats
155 DDPF_RGB
= $00000040; // used by RGB formats
156 DDPF_LUMINANCE
= $00020000; // used by formats like D3DFMT_L16
157 DDPF_BUMPLUMINANCE
= $00040000; // used by mixed signed-unsigned formats
158 DDPF_BUMPDUDV
= $00080000; // used by signed formats
160 { Constans used by TDDSCaps.Caps1.}
161 DDSCAPS_COMPLEX
= $00000008;
162 DDSCAPS_TEXTURE
= $00001000;
163 DDSCAPS_MIPMAP
= $00400000;
165 { Constans used by TDDSCaps.Caps2.}
166 DDSCAPS2_CUBEMAP
= $00000200;
167 DDSCAPS2_POSITIVEX
= $00000400;
168 DDSCAPS2_NEGATIVEX
= $00000800;
169 DDSCAPS2_POSITIVEY
= $00001000;
170 DDSCAPS2_NEGATIVEY
= $00002000;
171 DDSCAPS2_POSITIVEZ
= $00004000;
172 DDSCAPS2_NEGATIVEZ
= $00008000;
173 DDSCAPS2_VOLUME
= $00200000;
175 { Flags for TDDSurfaceDesc2.Flags used when saving DDS file.}
176 DDS_SAVE_FLAGS
= DDSD_CAPS
or DDSD_PIXELFORMAT
or DDSD_WIDTH
or
177 DDSD_HEIGHT
or DDSD_LINEARSIZE
;
180 { Stores the pixel format information.}
181 TDDPixelFormat
= packed record
182 Size
: LongWord; // Size of the structure = 32 bytes
183 Flags
: LongWord; // Flags to indicate valid fields
184 FourCC
: LongWord; // Four-char code for compressed textures (DXT)
185 BitCount
: LongWord; // Bits per pixel if uncomp. usually 16,24 or 32
186 RedMask
: LongWord; // Bit mask for the Red component
187 GreenMask
: LongWord; // Bit mask for the Green component
188 BlueMask
: LongWord; // Bit mask for the Blue component
189 AlphaMask
: LongWord; // Bit mask for the Alpha component
192 { Specifies capabilities of surface.}
193 TDDSCaps
= packed record
194 Caps1
: LongWord; // Should always include DDSCAPS_TEXTURE
195 Caps2
: LongWord; // For cubic environment maps
196 Reserved
: array[0..1] of LongWord; // Reserved
199 { Record describing DDS file contents.}
200 TDDSurfaceDesc2
= packed record
201 Size
: LongWord; // Size of the structure = 124 Bytes
202 Flags
: LongWord; // Flags to indicate valid fields
203 Height
: LongWord; // Height of the main image in pixels
204 Width
: LongWord; // Width of the main image in pixels
205 PitchOrLinearSize
: LongWord; // For uncomp formats number of bytes per
206 // scanline. For comp it is the size in
207 // bytes of the main image
208 Depth
: LongWord; // Only for volume text depth of the volume
209 MipMaps
: LongInt; // Total number of levels in the mipmap chain
210 Reserved1
: array[0..10] of LongWord; // Reserved
211 PixelFormat
: TDDPixelFormat
; // Format of the pixel data
212 Caps
: TDDSCaps
; // Capabilities
213 Reserved2
: LongWord; // Reserved
217 TDDSFileHeader
= packed record
218 Magic
: LongWord; // File format magic
219 Desc
: TDDSurfaceDesc2
; // Surface description
222 { Resoirce types for D3D 10+ }
223 TD3D10ResourceDimension
= (
224 D3D10_RESOURCE_DIMENSION_UNKNOWN
= 0,
225 D3D10_RESOURCE_DIMENSION_BUFFER
= 1,
226 D3D10_RESOURCE_DIMENSION_TEXTURE1D
= 2,
227 D3D10_RESOURCE_DIMENSION_TEXTURE2D
= 3,
228 D3D10_RESOURCE_DIMENSION_TEXTURE3D
= 4
231 { Texture formats for D3D 10+ }
233 DXGI_FORMAT_UNKNOWN
= 0,
234 DXGI_FORMAT_R32G32B32A32_TYPELESS
= 1,
235 DXGI_FORMAT_R32G32B32A32_FLOAT
= 2,
236 DXGI_FORMAT_R32G32B32A32_UINT
= 3,
237 DXGI_FORMAT_R32G32B32A32_SINT
= 4,
238 DXGI_FORMAT_R32G32B32_TYPELESS
= 5,
239 DXGI_FORMAT_R32G32B32_FLOAT
= 6,
240 DXGI_FORMAT_R32G32B32_UINT
= 7,
241 DXGI_FORMAT_R32G32B32_SINT
= 8,
242 DXGI_FORMAT_R16G16B16A16_TYPELESS
= 9,
243 DXGI_FORMAT_R16G16B16A16_FLOAT
= 10,
244 DXGI_FORMAT_R16G16B16A16_UNORM
= 11,
245 DXGI_FORMAT_R16G16B16A16_UINT
= 12,
246 DXGI_FORMAT_R16G16B16A16_SNORM
= 13,
247 DXGI_FORMAT_R16G16B16A16_SINT
= 14,
248 DXGI_FORMAT_R32G32_TYPELESS
= 15,
249 DXGI_FORMAT_R32G32_FLOAT
= 16,
250 DXGI_FORMAT_R32G32_UINT
= 17,
251 DXGI_FORMAT_R32G32_SINT
= 18,
252 DXGI_FORMAT_R32G8X24_TYPELESS
= 19,
253 DXGI_FORMAT_D32_FLOAT_S8X24_UINT
= 20,
254 DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS
= 21,
255 DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
= 22,
256 DXGI_FORMAT_R10G10B10A2_TYPELESS
= 23,
257 DXGI_FORMAT_R10G10B10A2_UNORM
= 24,
258 DXGI_FORMAT_R10G10B10A2_UINT
= 25,
259 DXGI_FORMAT_R11G11B10_FLOAT
= 26,
260 DXGI_FORMAT_R8G8B8A8_TYPELESS
= 27,
261 DXGI_FORMAT_R8G8B8A8_UNORM
= 28,
262 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
= 29,
263 DXGI_FORMAT_R8G8B8A8_UINT
= 30,
264 DXGI_FORMAT_R8G8B8A8_SNORM
= 31,
265 DXGI_FORMAT_R8G8B8A8_SINT
= 32,
266 DXGI_FORMAT_R16G16_TYPELESS
= 33,
267 DXGI_FORMAT_R16G16_FLOAT
= 34,
268 DXGI_FORMAT_R16G16_UNORM
= 35,
269 DXGI_FORMAT_R16G16_UINT
= 36,
270 DXGI_FORMAT_R16G16_SNORM
= 37,
271 DXGI_FORMAT_R16G16_SINT
= 38,
272 DXGI_FORMAT_R32_TYPELESS
= 39,
273 DXGI_FORMAT_D32_FLOAT
= 40,
274 DXGI_FORMAT_R32_FLOAT
= 41,
275 DXGI_FORMAT_R32_UINT
= 42,
276 DXGI_FORMAT_R32_SINT
= 43,
277 DXGI_FORMAT_R24G8_TYPELESS
= 44,
278 DXGI_FORMAT_D24_UNORM_S8_UINT
= 45,
279 DXGI_FORMAT_R24_UNORM_X8_TYPELESS
= 46,
280 DXGI_FORMAT_X24_TYPELESS_G8_UINT
= 47,
281 DXGI_FORMAT_R8G8_TYPELESS
= 48,
282 DXGI_FORMAT_R8G8_UNORM
= 49,
283 DXGI_FORMAT_R8G8_UINT
= 50,
284 DXGI_FORMAT_R8G8_SNORM
= 51,
285 DXGI_FORMAT_R8G8_SINT
= 52,
286 DXGI_FORMAT_R16_TYPELESS
= 53,
287 DXGI_FORMAT_R16_FLOAT
= 54,
288 DXGI_FORMAT_D16_UNORM
= 55,
289 DXGI_FORMAT_R16_UNORM
= 56,
290 DXGI_FORMAT_R16_UINT
= 57,
291 DXGI_FORMAT_R16_SNORM
= 58,
292 DXGI_FORMAT_R16_SINT
= 59,
293 DXGI_FORMAT_R8_TYPELESS
= 60,
294 DXGI_FORMAT_R8_UNORM
= 61,
295 DXGI_FORMAT_R8_UINT
= 62,
296 DXGI_FORMAT_R8_SNORM
= 63,
297 DXGI_FORMAT_R8_SINT
= 64,
298 DXGI_FORMAT_A8_UNORM
= 65,
299 DXGI_FORMAT_R1_UNORM
= 66,
300 DXGI_FORMAT_R9G9B9E5_SHAREDEXP
= 67,
301 DXGI_FORMAT_R8G8_B8G8_UNORM
= 68,
302 DXGI_FORMAT_G8R8_G8B8_UNORM
= 69,
303 DXGI_FORMAT_BC1_TYPELESS
= 70,
304 DXGI_FORMAT_BC1_UNORM
= 71,
305 DXGI_FORMAT_BC1_UNORM_SRGB
= 72,
306 DXGI_FORMAT_BC2_TYPELESS
= 73,
307 DXGI_FORMAT_BC2_UNORM
= 74,
308 DXGI_FORMAT_BC2_UNORM_SRGB
= 75,
309 DXGI_FORMAT_BC3_TYPELESS
= 76,
310 DXGI_FORMAT_BC3_UNORM
= 77,
311 DXGI_FORMAT_BC3_UNORM_SRGB
= 78,
312 DXGI_FORMAT_BC4_TYPELESS
= 79,
313 DXGI_FORMAT_BC4_UNORM
= 80,
314 DXGI_FORMAT_BC4_SNORM
= 81,
315 DXGI_FORMAT_BC5_TYPELESS
= 82,
316 DXGI_FORMAT_BC5_UNORM
= 83,
317 DXGI_FORMAT_BC5_SNORM
= 84,
318 DXGI_FORMAT_B5G6R5_UNORM
= 85,
319 DXGI_FORMAT_B5G5R5A1_UNORM
= 86,
320 DXGI_FORMAT_B8G8R8A8_UNORM
= 87,
321 DXGI_FORMAT_B8G8R8X8_UNORM
= 88,
322 DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
= 89,
323 DXGI_FORMAT_B8G8R8A8_TYPELESS
= 90,
324 DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
= 91,
325 DXGI_FORMAT_B8G8R8X8_TYPELESS
= 92,
326 DXGI_FORMAT_B8G8R8X8_UNORM_SRGB
= 93,
327 DXGI_FORMAT_BC6H_TYPELESS
= 94,
328 DXGI_FORMAT_BC6H_UF16
= 95,
329 DXGI_FORMAT_BC6H_SF16
= 96,
330 DXGI_FORMAT_BC7_TYPELESS
= 97,
331 DXGI_FORMAT_BC7_UNORM
= 98,
332 DXGI_FORMAT_BC7_UNORM_SRGB
= 99,
333 DXGI_FORMAT_AYUV
= 100,
334 DXGI_FORMAT_Y410
= 101,
335 DXGI_FORMAT_Y416
= 102,
336 DXGI_FORMAT_NV12
= 103,
337 DXGI_FORMAT_P010
= 104,
338 DXGI_FORMAT_P016
= 105,
339 DXGI_FORMAT_420_OPAQUE
= 106,
340 DXGI_FORMAT_YUY2
= 107,
341 DXGI_FORMAT_Y210
= 108,
342 DXGI_FORMAT_Y216
= 109,
343 DXGI_FORMAT_NV11
= 110,
344 DXGI_FORMAT_AI44
= 111,
345 DXGI_FORMAT_IA44
= 112,
346 DXGI_FORMAT_P8
= 113,
347 DXGI_FORMAT_A8P8
= 114,
348 DXGI_FORMAT_B4G4R4A4_UNORM
= 115
351 { DX10 extension header for DDS file format }
352 TDX10Header
= packed record
353 DXGIFormat
: TDXGIFormat
;
354 ResourceDimension
: TD3D10ResourceDimension
;
360 { TDDSFileFormat class implementation }
362 procedure TDDSFileFormat
.Define
;
365 FName
:= SDDSFormatName
;
366 FFeatures
:= [ffLoad
, ffSave
, ffMultiImage
];
367 FSupportedFormats
:= DDSSupportedFormats
;
369 FSaveCubeMap
:= False;
370 FSaveVolume
:= False;
371 FSaveMipMapCount
:= 1;
376 RegisterOption(ImagingDDSLoadedCubeMap
, @FLoadedCubeMap
);
377 RegisterOption(ImagingDDSLoadedVolume
, @FLoadedVolume
);
378 RegisterOption(ImagingDDSLoadedMipMapCount
, @FLoadedMipMapCount
);
379 RegisterOption(ImagingDDSLoadedDepth
, @FLoadedDepth
);
380 RegisterOption(ImagingDDSSaveCubeMap
, @FSaveCubeMap
);
381 RegisterOption(ImagingDDSSaveVolume
, @FSaveVolume
);
382 RegisterOption(ImagingDDSSaveMipMapCount
, @FSaveMipMapCount
);
383 RegisterOption(ImagingDDSSaveDepth
, @FSaveDepth
);
386 procedure TDDSFileFormat
.CheckOptionsValidity
;
389 FSaveVolume
:= False;
391 FSaveCubeMap
:= False;
392 if FSaveDepth
< 1 then
394 if FSaveMipMapCount
< 1 then
395 FSaveMipMapCount
:= 1;
398 procedure TDDSFileFormat
.ComputeSubDimensions(Idx
, Width
, Height
, MipMaps
, Depth
: LongInt;
399 IsCubeMap
, IsVolume
: Boolean; var CurWidth
, CurHeight
: LongInt);
401 I
, Last
, Shift
: LongInt;
411 // Cube maps are stored like this
419 // Modify index so later in for loop we iterate less times
420 Idx
:= Idx
- ((Idx
div MipMaps
) * MipMaps
);
422 for I
:= 0 to Idx
- 1 do
424 CurWidth
:= ClampInt(CurWidth
shr 1, 1, CurWidth
);
425 CurHeight
:= ClampInt(CurHeight
shr 1, 1, CurHeight
);
430 // Volume textures are stored in DDS files like this:
438 // Slice 0 mipmap 3 ...
441 while Idx
> Last
- 1 do
443 CurWidth
:= ClampInt(CurWidth
shr 1, 1, CurWidth
);
444 CurHeight
:= ClampInt(CurHeight
shr 1, 1, CurHeight
);
445 if (CurWidth
= 1) and (CurHeight
= 1) then
448 Inc(Last
, ClampInt(Depth
shr Shift
, 1, Depth
));
454 function TDDSFileFormat
.LoadData(Handle
: TImagingHandle
;
455 var Images
: TDynImageDataArray
; OnlyFirstLevel
: Boolean): Boolean;
458 HdrDX10
: TDX10Header
;
459 SrcFormat
: TImageFormat
;
460 FmtInfo
: TImageFormatInfo
;
461 NeedsSwapChannels
: Boolean;
462 CurrentWidth
, CurrentHeight
, ImageCount
, LoadSize
, I
,
463 PitchOrLinear
, MainImageLinearSize
: Integer;
466 UseAsLinear
: Boolean;
468 function MasksEqual(const DDPF
: TDDPixelFormat
; PF
: PPixelFormatInfo
): Boolean;
470 Result
:= (DDPF
.AlphaMask
= PF
.ABitMask
) and
471 (DDPF
.RedMask
= PF
.RBitMask
) and (DDPF
.GreenMask
= PF
.GBitMask
) and
472 (DDPF
.BlueMask
= PF
.BBitMask
);
475 function FindFourCCFormat(FourCC
: LongWord): TImageFormat
;
477 // Handle FourCC and large ARGB formats
479 D3DFMT_A16B16G16R16
: Result
:= ifA16B16G16R16
;
480 D3DFMT_R32F
: Result
:= ifR32F
;
481 D3DFMT_A32B32G32R32F
: Result
:= ifA32B32G32R32F
;
482 D3DFMT_R16F
: Result
:= ifR16F
;
483 D3DFMT_A16B16G16R16F
: Result
:= ifA16B16G16R16F
;
484 FOURCC_DXT1
: Result
:= ifDXT1
;
485 FOURCC_DXT3
: Result
:= ifDXT3
;
486 FOURCC_DXT5
: Result
:= ifDXT5
;
487 FOURCC_ATI1
: Result
:= ifATI1N
;
488 FOURCC_ATI2
: Result
:= ifATI2N
;
494 function FindDX10Format(DXGIFormat
: TDXGIFormat
; var NeedsSwapChannels
: Boolean): TImageFormat
;
497 NeedsSwapChannels
:= False;
500 DXGI_FORMAT_UNKNOWN
: ;
501 DXGI_FORMAT_R32G32B32A32_TYPELESS
, DXGI_FORMAT_R32G32B32A32_FLOAT
:
502 Result
:= ifA32B32G32R32F
;
503 DXGI_FORMAT_R32G32B32A32_UINT
: ;
504 DXGI_FORMAT_R32G32B32A32_SINT
: ;
505 DXGI_FORMAT_R32G32B32_TYPELESS
, DXGI_FORMAT_R32G32B32_FLOAT
:
506 Result
:= ifB32G32R32F
;
507 DXGI_FORMAT_R32G32B32_UINT
: ;
508 DXGI_FORMAT_R32G32B32_SINT
: ;
509 DXGI_FORMAT_R16G16B16A16_FLOAT
:
510 Result
:= ifA16B16G16R16F
;
511 DXGI_FORMAT_R16G16B16A16_TYPELESS
, DXGI_FORMAT_R16G16B16A16_UNORM
,
512 DXGI_FORMAT_R16G16B16A16_UINT
, DXGI_FORMAT_R16G16B16A16_SNORM
,
513 DXGI_FORMAT_R16G16B16A16_SINT
:
514 Result
:= ifA16B16G16R16
;
515 DXGI_FORMAT_R32G32_TYPELESS
: ;
516 DXGI_FORMAT_R32G32_FLOAT
: ;
517 DXGI_FORMAT_R32G32_UINT
: ;
518 DXGI_FORMAT_R32G32_SINT
: ;
519 DXGI_FORMAT_R32G8X24_TYPELESS
: ;
520 DXGI_FORMAT_D32_FLOAT_S8X24_UINT
: ;
521 DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS
: ;
522 DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
: ;
523 DXGI_FORMAT_R10G10B10A2_TYPELESS
: ;
524 DXGI_FORMAT_R10G10B10A2_UNORM
: ;
525 DXGI_FORMAT_R10G10B10A2_UINT
: ;
526 DXGI_FORMAT_R11G11B10_FLOAT
: ;
527 DXGI_FORMAT_R8G8B8A8_TYPELESS
, DXGI_FORMAT_R8G8B8A8_UNORM
,
528 DXGI_FORMAT_R8G8B8A8_UINT
, DXGI_FORMAT_R8G8B8A8_SNORM
,DXGI_FORMAT_R8G8B8A8_SINT
,
529 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
:
531 Result
:= ifA8R8G8B8
;
532 NeedsSwapChannels
:= True;
534 DXGI_FORMAT_R16G16_TYPELESS
: ;
535 DXGI_FORMAT_R16G16_FLOAT
: ;
536 DXGI_FORMAT_R16G16_UNORM
: ;
537 DXGI_FORMAT_R16G16_UINT
: ;
538 DXGI_FORMAT_R16G16_SNORM
: ;
539 DXGI_FORMAT_R16G16_SINT
: ;
540 DXGI_FORMAT_R32_TYPELESS
, DXGI_FORMAT_R32_UINT
, DXGI_FORMAT_R32_SINT
:
542 DXGI_FORMAT_D32_FLOAT
, DXGI_FORMAT_R32_FLOAT
:
544 DXGI_FORMAT_R24G8_TYPELESS
: ;
545 DXGI_FORMAT_D24_UNORM_S8_UINT
: ;
546 DXGI_FORMAT_R24_UNORM_X8_TYPELESS
: ;
547 DXGI_FORMAT_X24_TYPELESS_G8_UINT
: ;
548 DXGI_FORMAT_R8G8_TYPELESS
, DXGI_FORMAT_R8G8_UNORM
, DXGI_FORMAT_R8G8_UINT
,
549 DXGI_FORMAT_R8G8_SNORM
, DXGI_FORMAT_R8G8_SINT
:
551 DXGI_FORMAT_R16_TYPELESS
, DXGI_FORMAT_D16_UNORM
, DXGI_FORMAT_R16_UNORM
,
552 DXGI_FORMAT_R16_UINT
, DXGI_FORMAT_R16_SNORM
, DXGI_FORMAT_R16_SINT
:
554 DXGI_FORMAT_R16_FLOAT
:
556 DXGI_FORMAT_R8_TYPELESS
, DXGI_FORMAT_R8_UNORM
, DXGI_FORMAT_R8_UINT
,
557 DXGI_FORMAT_R8_SNORM
, DXGI_FORMAT_R8_SINT
, DXGI_FORMAT_A8_UNORM
:
559 DXGI_FORMAT_R1_UNORM
: ;
560 DXGI_FORMAT_R9G9B9E5_SHAREDEXP
: ;
561 DXGI_FORMAT_R8G8_B8G8_UNORM
: ;
562 DXGI_FORMAT_G8R8_G8B8_UNORM
: ;
563 DXGI_FORMAT_BC1_TYPELESS
, DXGI_FORMAT_BC1_UNORM
, DXGI_FORMAT_BC1_UNORM_SRGB
:
565 DXGI_FORMAT_BC2_TYPELESS
, DXGI_FORMAT_BC2_UNORM
, DXGI_FORMAT_BC2_UNORM_SRGB
:
567 DXGI_FORMAT_BC3_TYPELESS
, DXGI_FORMAT_BC3_UNORM
, DXGI_FORMAT_BC3_UNORM_SRGB
:
569 DXGI_FORMAT_BC4_TYPELESS
, DXGI_FORMAT_BC4_UNORM
, DXGI_FORMAT_BC4_SNORM
:
571 DXGI_FORMAT_BC5_TYPELESS
, DXGI_FORMAT_BC5_UNORM
, DXGI_FORMAT_BC5_SNORM
:
573 DXGI_FORMAT_B5G6R5_UNORM
:
575 DXGI_FORMAT_B5G5R5A1_UNORM
:
576 Result
:= ifA1R5G5B5
;
577 DXGI_FORMAT_B8G8R8A8_UNORM
, DXGI_FORMAT_B8G8R8A8_TYPELESS
:
578 Result
:= ifA8R8G8B8
;
579 DXGI_FORMAT_B8G8R8X8_UNORM
, DXGI_FORMAT_B8G8R8X8_TYPELESS
:
580 Result
:= ifX8R8G8B8
;
581 DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
: ;
582 DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
: ;
583 DXGI_FORMAT_B8G8R8X8_UNORM_SRGB
: ;
584 DXGI_FORMAT_BC6H_TYPELESS
: ;
585 DXGI_FORMAT_BC6H_UF16
: ;
586 DXGI_FORMAT_BC6H_SF16
: ;
587 DXGI_FORMAT_BC7_TYPELESS
: ;
588 DXGI_FORMAT_BC7_UNORM
: ;
589 DXGI_FORMAT_BC7_UNORM_SRGB
: ;
592 DXGI_FORMAT_B4G4R4A4_UNORM
:
593 Result
:= ifA4R4G4B4
;
600 FLoadedMipMapCount
:= 1;
602 FLoadedVolume
:= False;
603 FLoadedCubeMap
:= False;
604 ZeroMemory(@HdrDX10
, SizeOf(HdrDX10
));
606 with GetIO
, Hdr
, Hdr
.Desc
.PixelFormat
do
608 Read(Handle
, @Hdr
, SizeOf(Hdr
));
610 SrcFormat
:= ifUnknown
;
611 NeedsSwapChannels
:= False;
613 // Get image data format
614 if (Flags
and DDPF_FOURCC
) = DDPF_FOURCC
then
616 if FourCC
= FOURCC_DX10
then
618 Read(Handle
, @HdrDX10
, SizeOf(HdrDX10
));
619 SrcFormat
:= FindDX10Format(HdrDX10
.DXGIFormat
, NeedsSwapChannels
);
620 FMetadata
.SetMetaItem(SMetaDdsDxgiFormat
, HdrDX10
.DXGIFormat
);
621 FMetadata
.SetMetaItem(SMetaDdsArraySize
, HdrDX10
.ArraySize
);
624 SrcFormat
:= FindFourCCFormat(FourCC
);
626 else if (Flags
and DDPF_RGB
) = DDPF_RGB
then
628 // Handle RGB formats
629 if (Flags
and DDPF_ALPHAPIXELS
) = DDPF_ALPHAPIXELS
then
631 // Handle RGB with alpha formats
635 if MasksEqual(Desc
.PixelFormat
, GetFormatInfo(ifA4R4G4B4
).PixelFormat
) then
636 SrcFormat
:= ifA4R4G4B4
;
637 if MasksEqual(Desc
.PixelFormat
, GetFormatInfo(ifA1R5G5B5
).PixelFormat
) then
638 SrcFormat
:= ifA1R5G5B5
;
642 SrcFormat
:= ifA8R8G8B8
;
643 if BlueMask
= $00FF0000 then
644 NeedsSwapChannels
:= True;
650 // Handle RGB without alpha formats
653 if MasksEqual(Desc
.PixelFormat
,
654 GetFormatInfo(ifR3G3B2
).PixelFormat
) then
655 SrcFormat
:= ifR3G3B2
;
658 if MasksEqual(Desc
.PixelFormat
,
659 GetFormatInfo(ifX4R4G4B4
).PixelFormat
) then
660 SrcFormat
:= ifX4R4G4B4
;
661 if MasksEqual(Desc
.PixelFormat
,
662 GetFormatInfo(ifX1R5G5B5
).PixelFormat
) then
663 SrcFormat
:= ifX1R5G5B5
;
664 if MasksEqual(Desc
.PixelFormat
,
665 GetFormatInfo(ifR5G6B5
).PixelFormat
) then
666 SrcFormat
:= ifR5G6B5
;
668 24: SrcFormat
:= ifR8G8B8
;
671 SrcFormat
:= ifX8R8G8B8
;
672 if BlueMask
= $00FF0000 then
673 NeedsSwapChannels
:= True;
678 else if (Flags
and DDPF_LUMINANCE
) = DDPF_LUMINANCE
then
680 // Handle luminance formats
681 if (Flags
and DDPF_ALPHAPIXELS
) = DDPF_ALPHAPIXELS
then
683 // Handle luminance with alpha formats
684 if BitCount
= 16 then
685 SrcFormat
:= ifA8Gray8
;
689 // Handle luminance without alpha formats
691 8: SrcFormat
:= ifGray8
;
692 16: SrcFormat
:= ifGray16
;
696 else if (Flags
and DDPF_BUMPLUMINANCE
) = DDPF_BUMPLUMINANCE
then
698 // Handle mixed bump-luminance formats like D3DFMT_X8L8V8U8
701 if BlueMask
= $00FF0000 then
703 SrcFormat
:= ifX8R8G8B8
; // D3DFMT_X8L8V8U8
704 NeedsSwapChannels
:= True;
708 else if (Flags
and DDPF_BUMPDUDV
) = DDPF_BUMPDUDV
then
710 // Handle bumpmap formats like D3DFMT_Q8W8V8U8
712 16: SrcFormat
:= ifA8Gray8
; // D3DFMT_V8U8
714 if AlphaMask
= $FF000000 then
716 SrcFormat
:= ifA8R8G8B8
; // D3DFMT_Q8W8V8U8
717 NeedsSwapChannels
:= True;
719 64: SrcFormat
:= ifA16B16G16R16
; // D3DFMT_Q16W16V16U16
723 // If DDS format is not supported we will exit
724 if SrcFormat
= ifUnknown
then
727 // File contains mipmaps for each subimage.
728 { Some DDS writers ignore setting proper Caps and Flags so
729 this check is not usable:
730 if ((Desc.Caps.Caps1 and DDSCAPS_MIPMAP) = DDSCAPS_MIPMAP) and
731 ((Desc.Flags and DDSD_MIPMAPCOUNT) = DDSD_MIPMAPCOUNT) then}
732 if Desc
.MipMaps
> 1 then
734 FLoadedMipMapCount
:= Desc
.MipMaps
;
735 FMetadata
.SetMetaItem(SMetaDdsMipMapCount
, Desc
.MipMaps
);
736 ImageCount
:= Desc
.MipMaps
;
739 // File stores volume texture
740 if ((Desc
.Caps
.Caps2
and DDSCAPS2_VOLUME
) = DDSCAPS2_VOLUME
) and
741 ((Desc
.Flags
and DDSD_DEPTH
) = DDSD_DEPTH
) then
743 FLoadedVolume
:= True;
744 FLoadedDepth
:= Desc
.Depth
;
745 ImageCount
:= GetVolumeLevelCount(Desc
.Depth
, ImageCount
);
748 // File stores cube texture
749 if (Desc
.Caps
.Caps2
and DDSCAPS2_CUBEMAP
) = DDSCAPS2_CUBEMAP
then
751 FLoadedCubeMap
:= True;
753 if (Desc
.Caps
.Caps2
and DDSCAPS2_POSITIVEX
) = DDSCAPS2_POSITIVEX
then Inc(I
);
754 if (Desc
.Caps
.Caps2
and DDSCAPS2_POSITIVEY
) = DDSCAPS2_POSITIVEY
then Inc(I
);
755 if (Desc
.Caps
.Caps2
and DDSCAPS2_POSITIVEZ
) = DDSCAPS2_POSITIVEZ
then Inc(I
);
756 if (Desc
.Caps
.Caps2
and DDSCAPS2_NEGATIVEX
) = DDSCAPS2_NEGATIVEX
then Inc(I
);
757 if (Desc
.Caps
.Caps2
and DDSCAPS2_NEGATIVEY
) = DDSCAPS2_NEGATIVEY
then Inc(I
);
758 if (Desc
.Caps
.Caps2
and DDSCAPS2_NEGATIVEZ
) = DDSCAPS2_NEGATIVEZ
then Inc(I
);
760 ImageCount
:= ImageCount
* I
;
763 // Allocate and load all images in file
764 FmtInfo
:= GetFormatInfo(SrcFormat
);
765 SetLength(Images
, ImageCount
);
767 // Compute the pitch or get if from file if present
768 UseAsPitch
:= (Desc
.Flags
and DDSD_PITCH
) = DDSD_PITCH
;
769 UseAsLinear
:= (Desc
.Flags
and DDSD_LINEARSIZE
) = DDSD_LINEARSIZE
;
770 // Use linear as default if none is set
771 if not UseAsPitch
and not UseAsLinear
then
773 // Main image pitch or linear size
774 PitchOrLinear
:= Desc
.PitchOrLinearSize
;
776 // Check: some writers just write garbage to pitch/linear size fields and flags
777 MainImageLinearSize
:= FmtInfo
.GetPixelsSize(SrcFormat
, Desc
.Width
, Desc
.Height
);
778 if UseAsLinear
and ((PitchOrLinear
< MainImageLinearSize
) or
779 (PitchOrLinear
* Integer(Desc
.Height
) = MainImageLinearSize
)) then
781 // Explicitly set linear size
782 PitchOrLinear
:= MainImageLinearSize
;
785 for I
:= 0 to ImageCount
- 1 do
787 // Compute dimensions of surrent subimage based on texture type and
789 ComputeSubDimensions(I
, Desc
.Width
, Desc
.Height
, Desc
.MipMaps
, Desc
.Depth
,
790 FLoadedCubeMap
, FLoadedVolume
, CurrentWidth
, CurrentHeight
);
791 NewImage(CurrentWidth
, CurrentHeight
, SrcFormat
, Images
[I
]);
793 if (I
> 0) or (PitchOrLinear
= 0) then
795 // Compute pitch or linear size for mipmap levels, or even for main image
796 // since some formats do not fill pitch nor size
798 PitchOrLinear
:= FmtInfo
.GetPixelsSize(SrcFormat
, CurrentWidth
, CurrentHeight
)
800 PitchOrLinear
:= (CurrentWidth
* FmtInfo
.BytesPerPixel
+ 3) div 4 * 4; // must be DWORD aligned
804 LoadSize
:= PitchOrLinear
806 LoadSize
:= CurrentHeight
* PitchOrLinear
;
808 if UseAsLinear
or (LoadSize
= Images
[I
].Size
) then
810 // If DDS does not use Pitch we can simply copy data
811 Read(Handle
, Images
[I
].Bits
, LoadSize
)
815 // If DDS uses Pitch we must load aligned scanlines
816 // and then remove padding
817 GetMem(Data
, LoadSize
);
819 Read(Handle
, Data
, LoadSize
);
820 RemovePadBytes(Data
, Images
[I
].Bits
, CurrentWidth
, CurrentHeight
,
821 FmtInfo
.BytesPerPixel
, PitchOrLinear
);
827 if NeedsSwapChannels
then
828 SwapChannels(Images
[I
], ChannelRed
, ChannelBlue
);
834 function TDDSFileFormat
.SaveData(Handle
: TImagingHandle
;
835 const Images
: TDynImageDataArray
; Index
: LongInt): Boolean;
838 MainImage
, ImageToSave
: TImageData
;
839 I
, MainIdx
, Len
, ImageCount
: LongInt;
841 FmtInfo
: TImageFormatInfo
;
842 MustBeFreed
: Boolean;
843 Is2DTexture
, IsCubeMap
, IsVolume
: Boolean;
844 MipMapCount
, CurrentWidth
, CurrentHeight
: LongInt;
845 NeedsResize
: Boolean;
846 NeedsConvert
: Boolean;
849 FillChar(Hdr
, Sizeof(Hdr
), 0);
851 MainIdx
:= FFirstIdx
;
852 Len
:= FLastIdx
- MainIdx
+ 1;
853 // Some DDS saving rules:
854 // 2D textures: Len is used as mipmap count (FSaveMipMapCount not used!).
855 // Cube maps: FSaveDepth * FSaveMipMapCount images are used, if Len is
856 // smaller than this file is saved as regular 2D texture.
857 // Volume maps: GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount) images are
858 // used, if Len is smaller than this file is
859 // saved as regular 2D texture.
861 IsCubeMap
:= FSaveCubeMap
;
862 IsVolume
:= FSaveVolume
;
863 MipMapCount
:= FSaveMipMapCount
;
867 // Check if we have enough images on Input to save cube map
868 if Len
< FSaveDepth
* FSaveMipMapCount
then
871 else if IsVolume
then
873 // Check if we have enough images on Input to save volume texture
874 if Len
< GetVolumeLevelCount(FSaveDepth
, FSaveMipMapCount
) then
878 Is2DTexture
:= not IsCubeMap
and not IsVolume
;
881 // Get number of mipmaps used with 2D texture
882 MipMapCount
:= Min(Len
, GetNumMipMapLevels(Images
[MainIdx
].Width
, Images
[MainIdx
].Height
));
885 // we create compatible main image and fill headers
886 if MakeCompatible(Images
[MainIdx
], MainImage
, MustBeFreed
) then
887 with GetIO
, MainImage
, Hdr
do
889 FmtInfo
:= GetFormatInfo(Format
);
891 Desc
.Size
:= SizeOf(Desc
);
893 Desc
.Height
:= Height
;
894 Desc
.Flags
:= DDS_SAVE_FLAGS
;
895 Desc
.Caps
.Caps1
:= DDSCAPS_TEXTURE
;
896 Desc
.PixelFormat
.Size
:= SizeOf(Desc
.PixelFormat
);
897 Desc
.PitchOrLinearSize
:= MainImage
.Size
;
898 ImageCount
:= MipMapCount
;
900 if MipMapCount
> 1 then
902 // Set proper flags if we have some mipmaps to be saved
903 Desc
.Flags
:= Desc
.Flags
or DDSD_MIPMAPCOUNT
;
904 Desc
.Caps
.Caps1
:= Desc
.Caps
.Caps1
or DDSCAPS_MIPMAP
or DDSCAPS_COMPLEX
;
905 Desc
.MipMaps
:= MipMapCount
;
910 // Set proper cube map flags - number of stored faces is taken
912 Desc
.Caps
.Caps1
:= Desc
.Caps
.Caps1
or DDSCAPS_COMPLEX
;
913 Desc
.Caps
.Caps2
:= Desc
.Caps
.Caps2
or DDSCAPS2_CUBEMAP
;
914 J
:= DDSCAPS2_POSITIVEX
;
915 for I
:= 0 to FSaveDepth
- 1 do
917 Desc
.Caps
.Caps2
:= Desc
.Caps
.Caps2
or J
;
920 ImageCount
:= FSaveDepth
* FSaveMipMapCount
;
922 else if IsVolume
then
924 // Set proper flags for volume texture
925 Desc
.Flags
:= Desc
.Flags
or DDSD_DEPTH
;
926 Desc
.Caps
.Caps1
:= Desc
.Caps
.Caps1
or DDSCAPS_COMPLEX
;
927 Desc
.Caps
.Caps2
:= Desc
.Caps
.Caps2
or DDSCAPS2_VOLUME
;
928 Desc
.Depth
:= FSaveDepth
;
929 ImageCount
:= GetVolumeLevelCount(FSaveDepth
, FSaveMipMapCount
);
932 // Now we set DDS pixel format for main image
933 if FmtInfo
.IsSpecial
or FmtInfo
.IsFloatingPoint
or
934 (FmtInfo
.BytesPerPixel
> 4) then
936 Desc
.PixelFormat
.Flags
:= DDPF_FOURCC
;
938 ifA16B16G16R16
: Desc
.PixelFormat
.FourCC
:= D3DFMT_A16B16G16R16
;
939 ifR32F
: Desc
.PixelFormat
.FourCC
:= D3DFMT_R32F
;
940 ifA32B32G32R32F
: Desc
.PixelFormat
.FourCC
:= D3DFMT_A32B32G32R32F
;
941 ifR16F
: Desc
.PixelFormat
.FourCC
:= D3DFMT_R16F
;
942 ifA16B16G16R16F
: Desc
.PixelFormat
.FourCC
:= D3DFMT_A16B16G16R16F
;
943 ifDXT1
: Desc
.PixelFormat
.FourCC
:= FOURCC_DXT1
;
944 ifDXT3
: Desc
.PixelFormat
.FourCC
:= FOURCC_DXT3
;
945 ifDXT5
: Desc
.PixelFormat
.FourCC
:= FOURCC_DXT5
;
946 ifATI1N
: Desc
.PixelFormat
.FourCC
:= FOURCC_ATI1
;
947 ifATI2N
: Desc
.PixelFormat
.FourCC
:= FOURCC_ATI2
;
950 else if FmtInfo
.HasGrayChannel
then
952 Desc
.PixelFormat
.Flags
:= DDPF_LUMINANCE
;
953 Desc
.PixelFormat
.BitCount
:= FmtInfo
.BytesPerPixel
* 8;
955 ifGray8
: Desc
.PixelFormat
.RedMask
:= 255;
956 ifGray16
: Desc
.PixelFormat
.RedMask
:= 65535;
959 Desc
.PixelFormat
.Flags
:= Desc
.PixelFormat
.Flags
or DDPF_ALPHAPIXELS
;
960 Desc
.PixelFormat
.RedMask
:= 255;
961 Desc
.PixelFormat
.AlphaMask
:= 65280;
967 Desc
.PixelFormat
.Flags
:= DDPF_RGB
;
968 Desc
.PixelFormat
.BitCount
:= FmtInfo
.BytesPerPixel
* 8;
969 if FmtInfo
.HasAlphaChannel
then
971 Desc
.PixelFormat
.Flags
:= Desc
.PixelFormat
.Flags
or DDPF_ALPHAPIXELS
;
972 Desc
.PixelFormat
.AlphaMask
:= $FF000000;
974 if FmtInfo
.BytesPerPixel
> 2 then
976 Desc
.PixelFormat
.RedMask
:= $00FF0000;
977 Desc
.PixelFormat
.GreenMask
:= $0000FF00;
978 Desc
.PixelFormat
.BlueMask
:= $000000FF;
982 Desc
.PixelFormat
.AlphaMask
:= FmtInfo
.PixelFormat
.ABitMask
;
983 Desc
.PixelFormat
.RedMask
:= FmtInfo
.PixelFormat
.RBitMask
;
984 Desc
.PixelFormat
.GreenMask
:= FmtInfo
.PixelFormat
.GBitMask
;
985 Desc
.PixelFormat
.BlueMask
:= FmtInfo
.PixelFormat
.BBitMask
;
989 // Header and main image are written to output
990 Write(Handle
, @Hdr
, SizeOf(Hdr
));
991 Write(Handle
, MainImage
.Bits
, MainImage
.Size
);
993 // Write the rest of the images and convert them to
994 // the same format as main image if necessary and ensure proper mipmap
996 for I
:= MainIdx
+ 1 to MainIdx
+ ImageCount
- 1 do
998 // Get proper dimensions for this level
999 ComputeSubDimensions(I
, Desc
.Width
, Desc
.Height
, Desc
.MipMaps
, Desc
.Depth
,
1000 IsCubeMap
, IsVolume
, CurrentWidth
, CurrentHeight
);
1002 // Check if input image for this level has the right size and format
1003 NeedsResize
:= not ((Images
[I
].Width
= CurrentWidth
) and (Images
[I
].Height
= CurrentHeight
));
1004 NeedsConvert
:= not (Images
[I
].Format
= Format
);
1006 if NeedsResize
or NeedsConvert
then
1008 // Input image must be resized or converted to different format
1009 // to become valid mipmap level
1010 InitImage(ImageToSave
);
1011 CloneImage(Images
[I
], ImageToSave
);
1012 if NeedsConvert
then
1013 ConvertImage(ImageToSave
, Format
);
1015 ResizeImage(ImageToSave
, CurrentWidth
, CurrentHeight
, rfBilinear
);
1018 // Input image can be used without any changes
1019 ImageToSave
:= Images
[I
];
1021 // Write level data and release temp image if necessary
1022 Write(Handle
, ImageToSave
.Bits
, ImageToSave
.Size
);
1023 if Images
[I
].Bits
<> ImageToSave
.Bits
then
1024 FreeImage(ImageToSave
);
1030 FreeImage(MainImage
);
1034 procedure TDDSFileFormat
.ConvertToSupported(var Image
: TImageData
;
1035 const Info
: TImageFormatInfo
);
1037 ConvFormat
: TImageFormat
;
1039 if Info
.IsIndexed
or Info
.IsSpecial
then
1040 // convert indexed and unsupported special formatd to A8R8G8B8
1041 ConvFormat
:= ifA8R8G8B8
1042 else if Info
.IsFloatingPoint
then
1044 if Info
.Format
= ifA16R16G16B16F
then
1045 // only swap channels here
1046 ConvFormat
:= ifA16B16G16R16F
1048 // convert other floating point formats to A32B32G32R32F
1049 ConvFormat
:= ifA32B32G32R32F
1051 else if Info
.HasGrayChannel
then
1053 if Info
.HasAlphaChannel
then
1054 // convert grayscale with alpha to A8Gray8
1055 ConvFormat
:= ifA8Gray8
1056 else if Info
.BytesPerPixel
= 1 then
1057 // convert 8bit grayscale to Gray8
1058 ConvFormat
:= ifGray8
1060 // convert 16-64bit grayscales to Gray16
1061 ConvFormat
:= ifGray16
;
1063 else if Info
.BytesPerPixel
> 4 then
1064 ConvFormat
:= ifA16B16G16R16
1065 else if Info
.HasAlphaChannel
then
1066 // convert the other images with alpha channel to A8R8G8B8
1067 ConvFormat
:= ifA8R8G8B8
1069 // convert the other formats to X8R8G8B8
1070 ConvFormat
:= ifX8R8G8B8
;
1072 ConvertImage(Image
, ConvFormat
);
1075 function TDDSFileFormat
.TestFormat(Handle
: TImagingHandle
): Boolean;
1077 Hdr
: TDDSFileHeader
;
1081 if Handle
<> nil then
1084 ReadCount
:= Read(Handle
, @Hdr
, SizeOf(Hdr
));
1085 Seek(Handle
, -ReadCount
, smFromCurrent
);
1086 Result
:= (Hdr
.Magic
= DDSMagic
) and (ReadCount
= SizeOf(Hdr
)) and
1087 ((Hdr
.Desc
.Caps
.Caps1
and DDSCAPS_TEXTURE
) = DDSCAPS_TEXTURE
);
1092 RegisterImageFileFormat(TDDSFileFormat
);
1097 -- TODOS ----------------------------------------------------
1100 -- 0.77.1 ----------------------------------------------------
1101 - Texture and D3D specific info stored in DDS is now available as metadata
1103 - Added support for loading DDS files with DX10 extension
1104 (http://msdn.microsoft.com/en-us/library/windows/desktop/bb943991(v=vs.85).aspx)
1105 and few compatibility fixes.
1107 -- 0.25.0 Changes/Bug Fixes ---------------------------------
1108 - Added support for 3Dc ATI1/2 formats.
1110 -- 0.23 Changes/Bug Fixes -----------------------------------
1111 - Saved DDS with mipmaps now correctly defineds COMPLEX flag.
1112 - Fixed loading of RGB DDS files that use pitch and have mipmaps -
1113 mipmaps were loaded wrongly.
1115 -- 0.21 Changes/Bug Fixes -----------------------------------
1116 - Changed saving behaviour a bit: mipmaps are inlcuded automatically for
1117 2D textures if input image array has more than 1 image (no need to
1118 set SaveMipMapCount manually).
1119 - Mipmap levels are now saved with proper dimensions when saving DDS files.
1120 - Made some changes to not be so strict when loading DDS files.
1121 Many programs seem to save them in non-standard format
1122 (by MS DDS File Reference).
1123 - Added missing ifX8R8G8B8 to SupportedFormats, MakeCompatible failed
1124 when image was converted to this format (inside).
1125 - MakeCompatible method moved to base class, put ConvertToSupported here.
1126 GetSupportedFormats removed, it is now set in constructor.
1127 - Fixed bug that sometimes saved non-standard DDS files and another
1128 one that caused crash when these files were loaded.
1129 - Changed extensions to filename masks.
1130 - Changed SaveData, LoadData, and MakeCompatible methods according
1131 to changes in base class in Imaging unit.
1133 -- 0.19 Changes/Bug Fixes -----------------------------------
1134 - added support for half-float image formats
1135 - change in LoadData to allow support for more images
1136 in one stream loading
1138 -- 0.17 Changes/Bug Fixes -----------------------------------
1139 - fixed bug in TestFormat which does not recognize many DDS files
1140 - changed pitch/linearsize handling in DDS loading code to
1141 load DDS files produced by NVidia's Photoshop plugin