1 //-------------------------------------------------------------------------------------
4 // DirectX Texture Library - Misc image operations
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 //-------------------------------------------------------------------------------------
22 static HRESULT _ComputeMSE( _In_ const Image& image1, _In_ const Image& image2,
23 _Out_ float& mse, _Out_opt_cap_c_(4) float* mseV )
25 if ( !image1.pixels || !image2.pixels )
28 assert( image1.width == image2.width && image1.height == image2.height );
29 assert( !IsCompressed( image1.format ) && !IsCompressed( image2.format ) );
31 const size_t width = image1.width;
33 ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*width)*2, 16 ) ) );
37 const uint8_t *pSrc1 = image1.pixels;
38 const size_t rowPitch1 = image1.rowPitch;
40 const uint8_t *pSrc2 = image2.pixels;
41 const size_t rowPitch2 = image2.rowPitch;
43 XMVECTOR acc = XMVectorZero();
45 for( size_t h = 0; h < image1.height; ++h )
47 XMVECTOR* ptr1 = scanline.get();
48 if ( !_LoadScanline( ptr1, width, pSrc1, rowPitch1, image1.format ) )
51 XMVECTOR* ptr2 = scanline.get() + width;
52 if ( !_LoadScanline( ptr2, width, pSrc2, rowPitch2, image2.format ) )
55 for( size_t i = 0; i < width; ++i, ++ptr1, ++ptr2 )
58 XMVECTOR v = XMVectorSubtract( *ptr1, *ptr2 );
59 acc = XMVectorMultiplyAdd( v, v, acc );
66 // MSE = sum[ (I1 - I2)^2 ] / w*h
67 XMVECTOR d = XMVectorReplicate( float(image1.width * image1.height) );
68 XMVECTOR v = XMVectorDivide( acc, d );
71 XMStoreFloat4( reinterpret_cast<XMFLOAT4*>( mseV ), v );
72 mse = mseV[0] + mseV[1] + mseV[2] + mseV[3];
77 XMStoreFloat4( &_mseV, v );
78 mse = _mseV.x + _mseV.y + _mseV.z + _mseV.w;
85 //=====================================================================================
87 //=====================================================================================
89 //-------------------------------------------------------------------------------------
90 // Copies a rectangle from one image into another
91 //-------------------------------------------------------------------------------------
92 HRESULT CopyRectangle( const Image& srcImage, const Rect& srcRect, const Image& dstImage, DWORD filter, size_t xOffset, size_t yOffset )
94 if ( !srcImage.pixels || !dstImage.pixels )
97 if ( IsCompressed( srcImage.format ) || IsCompressed( dstImage.format ) )
98 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
100 // Validate rectangle/offset
101 if ( !srcRect.w || !srcRect.h || ( (srcRect.x + srcRect.w) > srcImage.width ) || ( (srcRect.y + srcRect.h) > srcImage.height ) )
106 if ( ( (xOffset + srcRect.w) > dstImage.width ) || ( (yOffset + srcRect.h) > dstImage.height ) )
111 // Compute source bytes-per-pixel
112 size_t sbpp = BitsPerPixel( srcImage.format );
118 // We don't support monochrome (DXGI_FORMAT_R1_UNORM)
119 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
122 const uint8_t* pEndSrc = srcImage.pixels + srcImage.rowPitch*srcImage.height;
123 const uint8_t* pEndDest = dstImage.pixels + dstImage.rowPitch*dstImage.height;
126 sbpp = ( sbpp + 7 ) / 8;
128 const uint8_t* pSrc = srcImage.pixels + (srcRect.y * srcImage.rowPitch) + (srcRect.x * sbpp);
130 if ( srcImage.format == dstImage.format )
132 // Direct copy case (avoid intermediate conversions)
133 uint8_t* pDest = dstImage.pixels + (yOffset * dstImage.rowPitch) + (xOffset * sbpp);
134 const size_t copyW = srcRect.w * sbpp;
135 for( size_t h=0; h < srcRect.h; ++h )
137 if ( ( (pSrc+copyW) > pEndSrc ) || (pDest > pEndDest) )
140 memcpy_s( pDest, pEndDest - pDest, pSrc, copyW );
142 pSrc += srcImage.rowPitch;
143 pDest += dstImage.rowPitch;
149 // Compute destination bytes-per-pixel (not the same format as source)
150 size_t dbpp = BitsPerPixel( dstImage.format );
156 // We don't support monochrome (DXGI_FORMAT_R1_UNORM)
157 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
161 dbpp = ( dbpp + 7 ) / 8;
163 uint8_t* pDest = dstImage.pixels + (yOffset * dstImage.rowPitch) + (xOffset * dbpp);
165 ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcRect.w), 16 ) ) );
167 return E_OUTOFMEMORY;
169 const size_t copyS = srcRect.w * sbpp;
170 const size_t copyD = srcRect.w * dbpp;
172 for( size_t h=0; h < srcRect.h; ++h )
174 if ( ( (pSrc+copyS) > pEndSrc) || ((pDest+copyD) > pEndDest) )
177 if ( !_LoadScanline( scanline.get(), srcRect.w, pSrc, copyS, srcImage.format ) )
180 _ConvertScanline( scanline.get(), srcRect.w, dstImage.format, srcImage.format, filter );
182 if ( !_StoreScanline( pDest, copyD, dstImage.format, scanline.get(), srcRect.w ) )
185 pSrc += srcImage.rowPitch;
186 pDest += dstImage.rowPitch;
193 //-------------------------------------------------------------------------------------
194 // Computes the Mean-Squared-Error (MSE) between two images
195 //-------------------------------------------------------------------------------------
196 HRESULT ComputeMSE( const Image& image1, const Image& image2, float& mse, float* mseV )
198 if ( !image1.pixels || !image2.pixels )
201 if ( image1.width != image2.width || image1.height != image2.height )
204 if ( IsCompressed(image1.format) )
206 if ( IsCompressed(image2.format) )
208 // Case 1: both images are compressed, expand to RGBA32F
210 HRESULT hr = Decompress( image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp1 );
215 hr = Decompress( image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp2 );
219 const Image* img1 = temp1.GetImage(0,0,0);
220 const Image* img2 = temp2.GetImage(0,0,0);
221 if ( !img1 || !img2 )
224 return _ComputeMSE( *img1, *img2, mse, mseV );
228 // Case 2: image1 is compressed, expand to RGBA32F
230 HRESULT hr = Decompress( image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp );
234 const Image* img = temp.GetImage(0,0,0);
238 return _ComputeMSE( *img, image2, mse, mseV );
243 if ( IsCompressed(image2.format) )
245 // Case 3: image2 is compressed, expand to RGBA32F
247 HRESULT hr = Decompress( image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp );
251 const Image* img = temp.GetImage(0,0,0);
255 return _ComputeMSE( image1, *img, mse, mseV );
259 // Case 4: neither image is compressed
260 return _ComputeMSE( image1, image2, mse, mseV );