1 //-------------------------------------------------------------------------------------
4 // DirectX Texture Library - Image container
6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
7 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
11 // Copyright (c) Microsoft Corporation. All rights reserved.
13 // http://go.microsoft.com/fwlink/?LinkId=248926
14 //-------------------------------------------------------------------------------------
16 #include "DirectXTexP.h"
21 extern bool _CalculateMipLevels( _In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels );
22 extern bool _CalculateMipLevels3D( _In_ size_t width, _In_ size_t height, _In_ size_t depth, _Inout_ size_t& mipLevels );
24 //-------------------------------------------------------------------------------------
25 // Determines number of image array entries and pixel size
26 //-------------------------------------------------------------------------------------
27 void _DetermineImageArray( const TexMetadata& metadata, DWORD cpFlags,
28 size_t& nImages, size_t& pixelSize )
30 assert( metadata.width > 0 && metadata.height > 0 && metadata.depth > 0 );
31 assert( metadata.arraySize > 0 );
32 assert( metadata.mipLevels > 0 );
34 size_t _pixelSize = 0;
37 switch( metadata.dimension )
39 case TEX_DIMENSION_TEXTURE1D:
40 case TEX_DIMENSION_TEXTURE2D:
41 for( size_t item = 0; item < metadata.arraySize; ++item )
43 size_t w = metadata.width;
44 size_t h = metadata.height;
46 for( size_t level=0; level < metadata.mipLevels; ++level )
48 size_t rowPitch, slicePitch;
49 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
51 _pixelSize += slicePitch;
63 case TEX_DIMENSION_TEXTURE3D:
65 size_t w = metadata.width;
66 size_t h = metadata.height;
67 size_t d = metadata.depth;
69 for( size_t level=0; level < metadata.mipLevels; ++level )
71 size_t rowPitch, slicePitch;
72 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
74 for( size_t slice=0; slice < d; ++slice )
76 _pixelSize += slicePitch;
98 pixelSize = _pixelSize;
102 //-------------------------------------------------------------------------------------
103 // Fills in the image array entries
104 //-------------------------------------------------------------------------------------
105 bool _SetupImageArray( uint8_t *pMemory, size_t pixelSize,
106 const TexMetadata& metadata, DWORD cpFlags,
107 Image* images, size_t nImages )
110 assert( pixelSize > 0 );
111 assert( nImages > 0 );
117 uint8_t* pixels = pMemory;
118 const uint8_t* pEndBits = pMemory + pixelSize;
120 switch( metadata.dimension )
122 case TEX_DIMENSION_TEXTURE1D:
123 case TEX_DIMENSION_TEXTURE2D:
124 if (metadata.arraySize == 0 || metadata.mipLevels == 0)
129 for( size_t item = 0; item < metadata.arraySize; ++item )
131 size_t w = metadata.width;
132 size_t h = metadata.height;
134 for( size_t level=0; level < metadata.mipLevels; ++level )
136 if ( index >= nImages )
141 size_t rowPitch, slicePitch;
142 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
144 images[index].width = w;
145 images[index].height = h;
146 images[index].format = metadata.format;
147 images[index].rowPitch = rowPitch;
148 images[index].slicePitch = slicePitch;
149 images[index].pixels = pixels;
152 pixels += slicePitch;
153 if ( pixels > pEndBits )
167 case TEX_DIMENSION_TEXTURE3D:
169 if (metadata.mipLevels == 0 || metadata.depth == 0)
174 size_t w = metadata.width;
175 size_t h = metadata.height;
176 size_t d = metadata.depth;
178 for( size_t level=0; level < metadata.mipLevels; ++level )
180 size_t rowPitch, slicePitch;
181 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
183 for( size_t slice=0; slice < d; ++slice )
185 if ( index >= nImages )
190 // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA
191 // with all slices of a given miplevel being continuous in memory
192 images[index].width = w;
193 images[index].height = h;
194 images[index].format = metadata.format;
195 images[index].rowPitch = rowPitch;
196 images[index].slicePitch = slicePitch;
197 images[index].pixels = pixels;
200 pixels += slicePitch;
201 if ( pixels > pEndBits )
225 //=====================================================================================
226 // ScratchImage - Bitmap image container
227 //=====================================================================================
229 //-------------------------------------------------------------------------------------
231 //-------------------------------------------------------------------------------------
232 HRESULT ScratchImage::Initialize( const TexMetadata& mdata )
234 if ( !IsValid(mdata.format) || IsVideo(mdata.format) )
237 size_t mipLevels = mdata.mipLevels;
239 switch( mdata.dimension )
241 case TEX_DIMENSION_TEXTURE1D:
242 if ( !mdata.width || mdata.height != 1 || mdata.depth != 1 || !mdata.arraySize )
245 if ( !_CalculateMipLevels(mdata.width,1,mipLevels) )
249 case TEX_DIMENSION_TEXTURE2D:
250 if ( !mdata.width || !mdata.height || mdata.depth != 1 || !mdata.arraySize )
253 if ( mdata.miscFlags & TEX_MISC_TEXTURECUBE )
255 if ( (mdata.arraySize % 6) != 0 )
259 if ( !_CalculateMipLevels(mdata.width,mdata.height,mipLevels) )
263 case TEX_DIMENSION_TEXTURE3D:
264 if ( !mdata.width || !mdata.height || !mdata.depth || mdata.arraySize != 1 )
267 if ( !_CalculateMipLevels3D(mdata.width,mdata.height,mdata.depth,mipLevels) )
272 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
277 _metadata.width = mdata.width;
278 _metadata.height = mdata.height;
279 _metadata.depth = mdata.depth;
280 _metadata.arraySize = mdata.arraySize;
281 _metadata.mipLevels = mipLevels;
282 _metadata.miscFlags = mdata.miscFlags & TEX_MISC_TEXTURECUBE;
283 _metadata.format = mdata.format;
284 _metadata.dimension = mdata.dimension;
286 size_t pixelSize, nimages;
287 _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize );
289 _image = new Image[ nimages ];
291 return E_OUTOFMEMORY;
294 memset( _image, 0, sizeof(Image) * nimages );
296 _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
300 return E_OUTOFMEMORY;
303 if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) )
312 HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels )
314 if ( !IsValid(fmt) || IsVideo(fmt) || !length || !arraySize )
317 // 1D is a special case of the 2D case
318 HRESULT hr = Initialize2D( fmt, length, 1, arraySize, mipLevels );
322 _metadata.dimension = TEX_DIMENSION_TEXTURE1D;
327 HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels )
329 if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !arraySize )
332 if ( !_CalculateMipLevels(width,height,mipLevels) )
337 _metadata.width = width;
338 _metadata.height = height;
340 _metadata.arraySize = arraySize;
341 _metadata.mipLevels = mipLevels;
342 _metadata.miscFlags = 0;
343 _metadata.format = fmt;
344 _metadata.dimension = TEX_DIMENSION_TEXTURE2D;
346 size_t pixelSize, nimages;
347 _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize );
349 _image = new Image[ nimages ];
351 return E_OUTOFMEMORY;
354 memset( _image, 0, sizeof(Image) * nimages );
356 _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
360 return E_OUTOFMEMORY;
363 if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) )
372 HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height, size_t depth, size_t mipLevels )
374 if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !depth )
377 if ( !_CalculateMipLevels3D(width,height,depth,mipLevels) )
382 _metadata.width = width;
383 _metadata.height = height;
384 _metadata.depth = depth;
385 _metadata.arraySize = 1; // Direct3D 10.x/11 does not support arrays of 3D textures
386 _metadata.mipLevels = mipLevels;
387 _metadata.miscFlags = 0;
388 _metadata.format = fmt;
389 _metadata.dimension = TEX_DIMENSION_TEXTURE3D;
391 size_t pixelSize, nimages;
392 _DetermineImageArray( _metadata, CP_FLAGS_NONE, nimages, pixelSize );
394 _image = new Image[ nimages ];
398 return E_OUTOFMEMORY;
401 memset( _image, 0, sizeof(Image) * nimages );
403 _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
407 return E_OUTOFMEMORY;
411 if ( !_SetupImageArray( _memory, pixelSize, _metadata, CP_FLAGS_NONE, _image, nimages ) )
420 HRESULT ScratchImage::InitializeCube( DXGI_FORMAT fmt, size_t width, size_t height, size_t nCubes, size_t mipLevels )
422 if ( !IsValid(fmt) || IsVideo(fmt) || !width || !height || !nCubes )
425 // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube
426 HRESULT hr = Initialize2D( fmt, width, height, nCubes * 6, mipLevels );
430 _metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
435 HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D )
437 HRESULT hr = ( srcImage.height > 1 || !allow1D )
438 ? Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1 )
439 : Initialize1D( srcImage.format, srcImage.width, 1, 1 );
444 const uint8_t* sptr = reinterpret_cast<const uint8_t*>( srcImage.pixels );
448 uint8_t* dptr = reinterpret_cast<uint8_t*>( _image[0].pixels );
452 for( size_t y = 0; y < srcImage.height; ++y )
454 _CopyScanline( dptr, _image[0].rowPitch, sptr, srcImage.rowPitch, srcImage.format, TEXP_SCANLINE_NONE );
455 sptr += srcImage.rowPitch;
456 dptr += _image[0].rowPitch;
462 HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nImages, bool allow1D )
464 if ( !images || !nImages )
467 DXGI_FORMAT format = images[0].format;
468 size_t width = images[0].width;
469 size_t height = images[0].height;
471 for( size_t index=0; index < nImages; ++index )
473 if ( !images[index].pixels )
476 if ( images[index].format != format || images[index].width != width || images[index].height != height )
478 // All images must be the same format, width, and height
483 HRESULT hr = ( height > 1 || !allow1D )
484 ? Initialize2D( format, width, height, nImages, 1 )
485 : Initialize1D( format, width, nImages, 1 );
490 for( size_t index=0; index < nImages; ++index )
492 const uint8_t* sptr = reinterpret_cast<const uint8_t*>( images[index].pixels );
496 assert( index < _nimages );
497 uint8_t* dptr = reinterpret_cast<uint8_t*>( _image[index].pixels );
501 for( size_t y = 0; y < height; ++y )
503 _CopyScanline( dptr, _image[index].rowPitch, sptr, images[index].rowPitch, format, TEXP_SCANLINE_NONE );
504 sptr += images[index].rowPitch;
505 dptr += _image[index].rowPitch;
512 HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nImages )
514 if ( !images || !nImages )
517 // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube
518 if ( ( nImages % 6 ) != 0 )
521 HRESULT hr = InitializeArrayFromImages( images, nImages, false );
525 _metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
530 HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth )
532 if ( !images || !depth )
535 DXGI_FORMAT format = images[0].format;
536 size_t width = images[0].width;
537 size_t height = images[0].height;
539 for( size_t slice=0; slice < depth; ++slice )
541 if ( !images[slice].pixels )
544 if ( images[slice].format != format || images[slice].width != width || images[slice].height != height )
546 // All images must be the same format, width, and height
551 HRESULT hr = Initialize3D( format, width, height, depth, 1 );
555 for( size_t slice=0; slice < depth; ++slice )
557 const uint8_t* sptr = reinterpret_cast<const uint8_t*>( images[slice].pixels );
561 assert( slice < _nimages );
562 uint8_t* dptr = reinterpret_cast<uint8_t*>( _image[slice].pixels );
566 for( size_t y = 0; y < height; ++y )
568 _CopyScanline( dptr, _image[slice].rowPitch, sptr, images[slice].rowPitch, format, TEXP_SCANLINE_NONE );
569 sptr += images[slice].rowPitch;
570 dptr += _image[slice].rowPitch;
577 void ScratchImage::Release()
590 _aligned_free( _memory );
594 memset(&_metadata, 0, sizeof(_metadata));
597 bool ScratchImage::OverrideFormat( DXGI_FORMAT f )
602 if ( !IsValid( f ) || IsVideo( f ) )
605 if ( ( BitsPerPixel( f ) != BitsPerPixel( _metadata.format ) )
606 || ( IsCompressed( f ) != IsCompressed( _metadata.format ) )
607 || ( IsPacked( f ) != IsPacked( _metadata.format ) ) )
609 // Can't change the effective pitch of the format this way
613 for( size_t index = 0; index < _nimages; ++index )
615 _image[ index ].format = f;
618 _metadata.format = f;
623 const Image* ScratchImage::GetImage(size_t mip, size_t item, size_t slice) const
625 if ( mip >= _metadata.mipLevels )
630 switch( _metadata.dimension )
632 case TEX_DIMENSION_TEXTURE1D:
633 case TEX_DIMENSION_TEXTURE2D:
637 if ( item >= _metadata.arraySize )
640 index = item*( _metadata.mipLevels ) + mip;
643 case TEX_DIMENSION_TEXTURE3D:
646 // No support for arrays of volumes
651 size_t d = _metadata.depth;
653 for( size_t level = 0; level < mip; ++level )
671 return &_image[index];