├── .gitattributes ├── 3rdparty └── FreeImage │ ├── FreeImage.dll │ ├── FreeImage.h │ └── FreeImage.lib ├── ProgImgView.sln ├── ProgImgView.vcxproj ├── README.md ├── baseWindow.h ├── compareWindow.cpp ├── compareWindow.h ├── imageWindow.cpp ├── imageWindow.h ├── main.cpp ├── mainWindow.cpp ├── mainWindow.h ├── moc.bat ├── moc_compareWindow.cpp ├── moc_imageWindow.cpp ├── moc_mainWindow.cpp ├── readme └── compare.jpg ├── stdafx.cpp ├── stdafx.h ├── util.cpp └── util.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /3rdparty/FreeImage/FreeImage.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knarkowicz/ProgImgView/54c76f7fa7fb0bd80a0b7a9deafccdfa8f71f583/3rdparty/FreeImage/FreeImage.dll -------------------------------------------------------------------------------- /3rdparty/FreeImage/FreeImage.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knarkowicz/ProgImgView/54c76f7fa7fb0bd80a0b7a9deafccdfa8f71f583/3rdparty/FreeImage/FreeImage.h -------------------------------------------------------------------------------- /3rdparty/FreeImage/FreeImage.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knarkowicz/ProgImgView/54c76f7fa7fb0bd80a0b7a9deafccdfa8f71f583/3rdparty/FreeImage/FreeImage.lib -------------------------------------------------------------------------------- /ProgImgView.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProgImgView", "ProgImgView.vcxproj", "{84EA7913-003F-4092-AEF2-C2A0914B7C9C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {84EA7913-003F-4092-AEF2-C2A0914B7C9C}.Debug|x64.ActiveCfg = Debug|x64 15 | {84EA7913-003F-4092-AEF2-C2A0914B7C9C}.Debug|x64.Build.0 = Debug|x64 16 | {84EA7913-003F-4092-AEF2-C2A0914B7C9C}.Release|x64.ActiveCfg = Release|x64 17 | {84EA7913-003F-4092-AEF2-C2A0914B7C9C}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ProgImgView.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {84EA7913-003F-4092-AEF2-C2A0914B7C9C} 23 | ProgImgView 24 | 25 | 26 | 27 | Application 28 | true 29 | v120 30 | MultiByte 31 | 32 | 33 | Application 34 | false 35 | v120 36 | true 37 | MultiByte 38 | 39 | 40 | v120 41 | 42 | 43 | v120 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Level3 59 | Disabled 60 | true 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | Level3 69 | MaxSpeed 70 | true 71 | true 72 | true 73 | 74 | 75 | true 76 | true 77 | true 78 | 79 | 80 | 81 | 82 | A:\qt\qt_5_7_0\qtbase\include\QtWidgets;A:\qt\qt_5_7_0\qt5-x64-shared-debug\include;%(AdditionalIncludeDirectories) 83 | MultiThreadedDebugDLL 84 | Disabled 85 | Use 86 | 87 | 88 | A:\qt\qt_5_7_0\qt5-x64-shared-debug\lib;DirectXTex\DirectXTex\Bin\Desktop_2013\x64\Debug;3rdparty\FreeImage;%(AdditionalLibraryDirectories) 89 | Qt5Widgetsd.lib;Qt5Cored.lib;Qt5Guid.lib;DirectXTex.lib;FreeImage.lib;%(AdditionalDependencies) 90 | true 91 | Windows 92 | 93 | 94 | 95 | 96 | A:\qt\qt_5_7_0\qtbase\include\QtWidgets;A:\qt\qt_5_7_0\qt5-x64-shared-release\include;%(AdditionalIncludeDirectories) 97 | Use 98 | 99 | 100 | A:\qt\qt_5_7_0\qt5-x64-shared-release\lib;DirectXTex\DirectXTex\Bin\Desktop_2013\x64\Release;3rdparty\FreeImage;%(AdditionalLibraryDirectories) 101 | Qt5Widgets.lib;Qt5Core.lib;Qt5Gui.lib;DirectXTex.lib;FreeImage.lib;%(AdditionalDependencies) 102 | true 103 | Windows 104 | Default 105 | 106 | 107 | 108 | 109 | 110 | 111 | Use 112 | Use 113 | 114 | 115 | 116 | 117 | 118 | 119 | Create 120 | Create 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ProgImgView 2 | ======= 3 | 4 | Simple tool for viewing and comparing images. Based on DirectXTex, FreeImage and QT. 5 | 6 | Binary can be downloaded from the releases tab. 7 | 8 | ## Features 9 | * Load dds, png, tga, jpg, bmp, hdr and ext images 10 | * Supports all uncommon dds formats (R32G32B32A32_UINT, R11G11B10_FLOAT, D24_UNORM_S8_UINT, R32G32B32A32_FLOAT, R8B8_SInt...) 11 | * Compare images 12 | * Texel picking 13 | * Reload opened image 14 | * Zoom 15 | * View single color channel or alpha channel 16 | * View selected mip map 17 | * View selected cube map face or texture array level 18 | * Drap and drop images 19 | * Open images from command line argument 20 | 21 | ![](https://raw.github.com/knarkowicz/ProgImgView/master/readme/compare.jpg) 22 | -------------------------------------------------------------------------------- /baseWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class EViewChannel : uint8_t 4 | { 5 | RGB, 6 | R, 7 | G, 8 | B, 9 | A 10 | }; 11 | 12 | class CBaseWindow 13 | { 14 | public: 15 | virtual void Reload() = 0; 16 | virtual void ZoomIn() = 0; 17 | virtual void ZoomOut() = 0; 18 | virtual void SetViewChannel( EViewChannel channel ) = 0; 19 | virtual void SetViewFace( unsigned face ) = 0; 20 | virtual void SetViewMipMap( unsigned mipMap ) = 0; 21 | virtual void SetViewMin( float min ) = 0; 22 | virtual void SetViewMax( float max ) = 0; 23 | virtual void SetViewGamma( float gamma ) = 0; 24 | virtual void SetViewDiffMult( float mult ) = 0; 25 | virtual QSize GetInitialSize() const = 0; 26 | virtual QString const& GetTitle() const = 0; 27 | virtual EViewChannel GetViewChannel() const = 0; 28 | virtual unsigned GetMipNum() const = 0; 29 | virtual unsigned GetFaceNum() const = 0; 30 | virtual unsigned GetViewFace() const = 0; 31 | virtual unsigned GetViewMipMap() const = 0; 32 | virtual float GetViewMin() const = 0; 33 | virtual float GetViewMax() const = 0; 34 | virtual float GetViewGamma() const = 0; 35 | virtual float GetViewDiffMult() const = 0; 36 | }; -------------------------------------------------------------------------------- /compareWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "compareWindow.h" 3 | #include "mainWindow.h" 4 | #include "util.h" 5 | 6 | CCompareImageLabel::CCompareImageLabel() 7 | : m_zoom( 1.0f ) 8 | , m_crossPos( -1, -1 ) 9 | { 10 | QImage crossImage( 13, 13, QImage::Format::Format_RGBA8888 ); 11 | 12 | unsigned const maxX = crossImage.width() - 1; 13 | unsigned const maxY = crossImage.height() - 1; 14 | unsigned const midX = maxX / 2; 15 | unsigned const midY = maxY / 2; 16 | 17 | for ( unsigned x = 0; x < crossImage.height(); ++x ) 18 | { 19 | for ( unsigned y = 0; y < crossImage.width(); ++y ) 20 | { 21 | unsigned color = 0; 22 | if ( ( x == midX && ( y == 0 || y == maxX ) ) || ( y == midY && ( x == 0 || x == maxY ) ) ) 23 | { 24 | color = 0xFFFFFFFF; 25 | } 26 | else if ( x == midX || y == midY ) 27 | { 28 | color = 0xFF000000; 29 | } 30 | else if ( x == midX - 1 || x == midX + 1 || y == midY - 1 || y == midY + 1 ) 31 | { 32 | color = 0xFFFFFFFF; 33 | } 34 | 35 | crossImage.setPixel( x, y, color ); 36 | } 37 | } 38 | 39 | m_crossPixmap = QPixmap::fromImage( crossImage ); 40 | } 41 | 42 | void CCompareImageLabel::SetZoom( float zoom ) 43 | { 44 | m_zoom = zoom; 45 | } 46 | 47 | void CCompareImageLabel::SetCrossPos( QPoint const& pos ) 48 | { 49 | if ( m_crossPos != pos ) 50 | { 51 | m_crossPos = pos; 52 | repaint(); 53 | } 54 | } 55 | 56 | void CCompareImageLabel::SetImage( QImage const& image ) 57 | { 58 | m_pixmap = QPixmap::fromImage( image ); 59 | } 60 | 61 | void CCompareImageLabel::paintEvent( QPaintEvent* event ) 62 | { 63 | QPainter paint( this ); 64 | 65 | QRect dstRect( 0, 0, m_pixmap.width() * m_zoom, m_pixmap.height() * m_zoom ); 66 | QRect srcRect( 0, 0, m_pixmap.width(), m_pixmap.height() ); 67 | paint.drawPixmap( dstRect, m_pixmap, srcRect ); 68 | 69 | if ( m_crossPos.x() >= 0 ) 70 | { 71 | dstRect = QRect( m_crossPos.x() - m_crossPixmap.width() / 2, m_crossPos.y() - m_crossPixmap.height() / 2, m_crossPixmap.width(), m_crossPixmap.height() ); 72 | srcRect = QRect( 0, 0, m_crossPixmap.width(), m_crossPixmap.height() ); 73 | paint.drawPixmap( dstRect, m_crossPixmap, srcRect ); 74 | } 75 | } 76 | 77 | CCompareWindow::CCompareWindow() 78 | : m_zoom( 1.0f ) 79 | , m_viewChannel( EViewChannel::RGB ) 80 | , m_viewFace( 0 ) 81 | , m_viewMipMap( 0 ) 82 | , m_imageWidth( 0 ) 83 | , m_imageHeight( 0 ) 84 | , m_viewMin( 0.0f ) 85 | , m_viewMax( 1.0f ) 86 | , m_viewGamma( 1.0f ) 87 | , m_viewDiffMult( 1.0f ) 88 | , m_gridLayout( this ) 89 | , m_scrollBarH( Qt::Orientation::Horizontal ) 90 | , m_scrollBarV( Qt::Orientation::Vertical ) 91 | , m_rmse( 0.0f ) 92 | , m_dragEnabled( false ) 93 | , m_selection( QRubberBand::Shape::Rectangle, this ) 94 | { 95 | memset( &m_info, 0, sizeof( m_info ) ); 96 | setAttribute( Qt::WA_DeleteOnClose ); 97 | 98 | connect( m_scrollArea[ 0 ].horizontalScrollBar(), &QScrollBar::rangeChanged, this, &CCompareWindow::ScrollBarHRangeChanged ); 99 | connect( m_scrollArea[ 0 ].verticalScrollBar(), &QScrollBar::rangeChanged, this, &CCompareWindow::ScrollBarVRangeChanged ); 100 | connect( &m_scrollBarH, &QScrollBar::valueChanged, this, &CCompareWindow::ScrollBarHValueChanged ); 101 | connect( &m_scrollBarV, &QScrollBar::valueChanged, this, &CCompareWindow::ScrollBarVValueChanged ); 102 | 103 | m_scrollArea[ 0 ].setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 104 | m_scrollArea[ 0 ].setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 105 | m_scrollArea[ 1 ].setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 106 | m_scrollArea[ 1 ].setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 107 | m_scrollArea[ 2 ].setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 108 | m_scrollArea[ 2 ].setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 109 | m_scrollArea[ 0 ].setWidget( &m_imageLabel[ 0 ] ); 110 | m_scrollArea[ 1 ].setWidget( &m_imageLabel[ 1 ] ); 111 | m_scrollArea[ 2 ].setWidget( &m_imageLabel[ 2 ] ); 112 | 113 | m_gridLayout.setMargin( 0 ); 114 | m_gridLayout.setSpacing( 0 ); 115 | m_gridLayout.addWidget( &m_scrollArea[ 0 ], 0, 0 ); 116 | m_gridLayout.addWidget( &m_scrollArea[ 1 ], 0, 1 ); 117 | m_gridLayout.addWidget( &m_scrollArea[ 2 ], 0, 2 ); 118 | m_gridLayout.addWidget( &m_scrollBarV, 0, 3 ); 119 | m_gridLayout.addWidget( &m_scrollBarH, 1, 0, 1, 3 ); 120 | 121 | m_scrollArea[ 0 ].viewport()->installEventFilter( this ); 122 | m_scrollArea[ 1 ].viewport()->installEventFilter( this ); 123 | m_scrollArea[ 2 ].viewport()->installEventFilter( this ); 124 | } 125 | 126 | CCompareWindow::~CCompareWindow() 127 | { 128 | m_scrollArea[ 0 ].setWidget( nullptr ); 129 | m_scrollArea[ 1 ].setWidget( nullptr ); 130 | m_scrollArea[ 2 ].setWidget( nullptr ); 131 | } 132 | 133 | bool CCompareWindow::LoadFiles( QString const& path0, QString const& path1 ) 134 | { 135 | m_path[ 0 ] = path0; 136 | m_path[ 1 ] = path1; 137 | if ( !UtilLoadFile( m_scratchImage[ 0 ], m_info[ 0 ], m_formatName[ 0 ], m_fileName[ 0 ], m_texelSizeInBytes, path0 ) ) 138 | { 139 | memset( &m_info, 0, sizeof( m_info ) ); 140 | return false; 141 | } 142 | 143 | if ( !UtilLoadFile( m_scratchImage[ 1 ], m_info[ 1 ], m_formatName[ 1 ], m_fileName[ 1 ], m_texelSizeInBytes, path1 ) ) 144 | { 145 | memset( &m_info, 0, sizeof( m_info ) ); 146 | return false; 147 | } 148 | 149 | if ( m_info[ 0 ].format != m_info[ 1 ].format ) 150 | { 151 | QMessageBox::critical( nullptr, "Error", QString( "Can't compare images of different formats (%1 %2)" ).arg( m_formatName[ 0 ] ).arg( m_formatName[ 1 ] ) ); 152 | memset( &m_info, 0, sizeof( m_info ) ); 153 | return false; 154 | } 155 | 156 | if ( m_info[ 0 ].width != m_info[ 1 ].width || m_info[ 0 ].height != m_info[ 1 ].height ) 157 | { 158 | QMessageBox::critical( nullptr, "Error", QString( "Can't compare images of different sizes (%1x%2 %3x%4)" ).arg( m_info[ 0 ].width ).arg( m_info[ 0 ].height ).arg( m_info[ 1 ].width ).arg( m_info[ 1 ].height ) ); 159 | memset( &m_info, 0, sizeof( m_info ) ); 160 | return false; 161 | } 162 | 163 | if ( m_info[ 0 ].mipLevels != m_info[ 1 ].mipLevels ) 164 | { 165 | QMessageBox::critical( nullptr, "Error", QString( "Can't compare images with different mip map number (%1 %2)" ).arg( m_info[ 0 ].mipLevels ).arg( m_info[ 1 ].mipLevels ) ); 166 | memset( &m_info, 0, sizeof( m_info ) ); 167 | return false; 168 | } 169 | 170 | if ( m_info[ 0 ].arraySize != m_info[ 1 ].arraySize ) 171 | { 172 | QMessageBox::critical( nullptr, "Error", QString( "Can't compare images with different array size (%1 %2)" ).arg( m_info[ 0 ].arraySize ).arg( m_info[ 1 ].arraySize ) ); 173 | memset( &m_info, 0, sizeof( m_info ) ); 174 | return false; 175 | } 176 | 177 | ( (QMdiSubWindow*) parentWidget() )->setWindowTitle( m_path[ 0 ] + " | " + m_path[ 1 ] ); 178 | UpdateImage(); 179 | UpdateTitle(); 180 | return true; 181 | } 182 | 183 | void CCompareWindow::Reload() 184 | { 185 | LoadFiles( m_path[ 0 ], m_path[ 1 ] ); 186 | } 187 | 188 | void CCompareWindow::ZoomIn() 189 | { 190 | QWheelEvent event( QPointF( 0.0f, 0.0f ), 1, Qt::MouseButton::NoButton, 0 ); 191 | wheelEvent( &event ); 192 | } 193 | 194 | void CCompareWindow::ZoomOut() 195 | { 196 | QWheelEvent event( QPointF( 0.0f, 0.0f ), -1, Qt::MouseButton::NoButton, 0 ); 197 | wheelEvent( &event ); 198 | } 199 | 200 | void CCompareWindow::SetViewChannel( EViewChannel channel ) 201 | { 202 | if ( m_viewChannel != channel ) 203 | { 204 | m_viewChannel = channel; 205 | UpdateImage(); 206 | UpdateTitle(); 207 | } 208 | } 209 | 210 | void CCompareWindow::SetViewFace( unsigned face ) 211 | { 212 | if ( m_viewFace != face ) 213 | { 214 | m_viewFace = face; 215 | UpdateImage(); 216 | UpdateTitle(); 217 | } 218 | } 219 | 220 | void CCompareWindow::SetViewMipMap( unsigned mipMap ) 221 | { 222 | if ( m_viewMipMap != mipMap ) 223 | { 224 | m_viewMipMap = mipMap; 225 | UpdateImage(); 226 | UpdateTitle(); 227 | } 228 | } 229 | 230 | void CCompareWindow::SetViewMin( float min ) 231 | { 232 | if ( m_viewMin != min ) 233 | { 234 | m_viewMin = min; 235 | UpdateImage(); 236 | } 237 | } 238 | 239 | void CCompareWindow::SetViewMax( float max ) 240 | { 241 | if ( m_viewMax != max ) 242 | { 243 | m_viewMax = max; 244 | UpdateImage(); 245 | } 246 | } 247 | 248 | void CCompareWindow::SetViewGamma( float gamma ) 249 | { 250 | if ( m_viewGamma != gamma ) 251 | { 252 | m_viewGamma = gamma; 253 | UpdateImage(); 254 | } 255 | } 256 | 257 | void CCompareWindow::SetViewDiffMult( float mult ) 258 | { 259 | if ( m_viewDiffMult != mult ) 260 | { 261 | m_viewDiffMult = mult; 262 | UpdateImage(); 263 | } 264 | } 265 | 266 | void CCompareWindow::UpdateImage() 267 | { 268 | m_rmse = 0.0f; 269 | m_viewFace = std::min( m_viewFace, m_info[ 0 ].arraySize - 1 ); 270 | m_viewMipMap = std::min( m_viewMipMap, m_info[ 0 ].mipLevels - 1 ); 271 | 272 | DirectX::Image const* img[ 2 ]; 273 | img[ 0 ] = m_scratchImage[ 0 ].GetImage( m_viewMipMap, m_viewFace, 0 ); 274 | img[ 1 ] = m_scratchImage[ 1 ].GetImage( m_viewMipMap, m_viewFace, 0 ); 275 | 276 | uint8_t* srcPtr[ 2 ]; 277 | srcPtr[ 0 ] = img[ 0 ]->pixels; 278 | srcPtr[ 1 ] = img[ 1 ]->pixels; 279 | 280 | m_imageWidth = img[ 0 ]->width; 281 | m_imageHeight = img[ 0 ]->height; 282 | 283 | unsigned redIdx = 0; 284 | unsigned greenIdx = 1; 285 | unsigned blueIdx = 2; 286 | switch ( m_viewChannel ) 287 | { 288 | case EViewChannel::R: redIdx = greenIdx = blueIdx = 0; break; 289 | case EViewChannel::G: redIdx = greenIdx = blueIdx = 1; break; 290 | case EViewChannel::B: redIdx = greenIdx = blueIdx = 2; break; 291 | case EViewChannel::A: redIdx = greenIdx = blueIdx = 3; break; 292 | } 293 | 294 | float const viewScale = 1.0f / ( m_viewMax - m_viewMin ); 295 | uint8_t* dataU8[ 3 ]; 296 | dataU8[ 0 ] = new uint8_t[ m_imageWidth * m_imageHeight * 3 ]; 297 | dataU8[ 1 ] = new uint8_t[ m_imageWidth * m_imageHeight * 3 ]; 298 | dataU8[ 2 ] = new uint8_t[ m_imageWidth * m_imageHeight * 3 ]; 299 | 300 | uint8_t* dataPtr[ 3 ]; 301 | dataPtr[ 0 ] = dataU8[ 0 ]; 302 | dataPtr[ 1 ] = dataU8[ 1 ]; 303 | dataPtr[ 2 ] = dataU8[ 2 ]; 304 | 305 | auto AddTexel = [&]( float texel[ 2 ][ 4 ] ) 306 | { 307 | float const diffR = fabs( texel[ 1 ][ redIdx ] - texel[ 0 ][ redIdx ] ); 308 | float const diffG = fabs( texel[ 1 ][ greenIdx ] - texel[ 0 ][ greenIdx ] ); 309 | float const diffB = fabs( texel[ 1 ][ blueIdx ] - texel[ 0 ][ blueIdx ] ); 310 | m_rmse += diffR * diffR + diffG * diffG + diffB * diffB; 311 | 312 | for ( unsigned i = 0; i < 2; ++i ) 313 | { 314 | texel[ i ][ 0 ] = powf( ( texel[ i ][ 0 ] - m_viewMin ) * viewScale, m_viewGamma ); 315 | texel[ i ][ 1 ] = powf( ( texel[ i ][ 1 ] - m_viewMin ) * viewScale, m_viewGamma ); 316 | texel[ i ][ 2 ] = powf( ( texel[ i ][ 2 ] - m_viewMin ) * viewScale, m_viewGamma ); 317 | texel[ i ][ 3 ] = powf( ( texel[ i ][ 3 ] - m_viewMin ) * viewScale, m_viewGamma ); 318 | 319 | dataPtr[ i ][ 0 ] = (uint8_t) ClampF( texel[ i ][ redIdx ] * 255.0f + 0.5f, 0.0f, 255.0f ); 320 | dataPtr[ i ][ 1 ] = (uint8_t) ClampF( texel[ i ][ greenIdx ] * 255.0f + 0.5f, 0.0f, 255.0f ); 321 | dataPtr[ i ][ 2 ] = (uint8_t) ClampF( texel[ i ][ blueIdx ] * 255.0f + 0.5f, 0.0f, 255.0f ); 322 | 323 | dataPtr[ i ] += 3; 324 | } 325 | 326 | dataPtr[ 2 ][ 0 ] = (uint8_t) ClampF( diffR * m_viewDiffMult * 255.0f + 0.5f, 0.0f, 255.0f ); 327 | dataPtr[ 2 ][ 1 ] = (uint8_t) ClampF( diffG * m_viewDiffMult * 255.0f + 0.5f, 0.0f, 255.0f ); 328 | dataPtr[ 2 ][ 2 ] = (uint8_t) ClampF( diffB * m_viewDiffMult * 255.0f + 0.5f, 0.0f, 255.0f ); 329 | dataPtr[ 2 ] += 3; 330 | }; 331 | 332 | float texel[ 2 ][ 4 ]; 333 | switch ( m_info[ 0 ].format ) 334 | { 335 | case DXGI_FORMAT_R8_TYPELESS: 336 | case DXGI_FORMAT_R8_UNORM: 337 | case DXGI_FORMAT_R8_UINT: 338 | case DXGI_FORMAT_R8_SNORM: 339 | case DXGI_FORMAT_R8_SINT: 340 | { 341 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 342 | { 343 | ReadR8_UNorm( texel[ 0 ], srcPtr[ 0 ] ); 344 | ReadR8_UNorm( texel[ 1 ], srcPtr[ 1 ] ); 345 | AddTexel( texel ); 346 | } 347 | } 348 | break; 349 | 350 | case DXGI_FORMAT_R8G8_SNORM: 351 | case DXGI_FORMAT_R8G8_SINT: 352 | { 353 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 354 | { 355 | ReadR8G8_SNorm( texel[ 0 ], srcPtr[ 0 ] ); 356 | ReadR8G8_SNorm( texel[ 1 ], srcPtr[ 1 ] ); 357 | AddTexel( texel ); 358 | } 359 | } 360 | break; 361 | 362 | case DXGI_FORMAT_R8G8_UNORM: 363 | case DXGI_FORMAT_R8G8_UINT: 364 | case DXGI_FORMAT_R8G8_TYPELESS: 365 | { 366 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 367 | { 368 | ReadR8G8_UNorm( texel[ 0 ], srcPtr[ 0 ] ); 369 | ReadR8G8_UNorm( texel[ 1 ], srcPtr[ 1 ] ); 370 | AddTexel( texel ); 371 | } 372 | } 373 | break; 374 | 375 | case DXGI_FORMAT_B8G8R8A8_UNORM: 376 | case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: 377 | { 378 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 379 | { 380 | ReadB8G8R8A8_UNorm( texel[ 0 ], srcPtr[ 0 ] ); 381 | ReadB8G8R8A8_UNorm( texel[ 1 ], srcPtr[ 1 ] ); 382 | AddTexel( texel ); 383 | } 384 | } 385 | break; 386 | 387 | case DXGI_FORMAT_B8G8R8X8_UNORM: 388 | case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: 389 | { 390 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 391 | { 392 | ReadB8G8R8X8_UNorm( texel[ 0 ], srcPtr[ 0 ] ); 393 | ReadB8G8R8X8_UNorm( texel[ 1 ], srcPtr[ 1 ] ); 394 | AddTexel( texel ); 395 | } 396 | } 397 | break; 398 | 399 | case DXGI_FORMAT_R8G8B8A8_TYPELESS: 400 | case DXGI_FORMAT_R8G8B8A8_UINT: 401 | case DXGI_FORMAT_R8G8B8A8_UNORM: 402 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: 403 | { 404 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 405 | { 406 | ReadR8G8B8A8_UNorm( texel[ 0 ], srcPtr[ 0 ] ); 407 | ReadR8G8B8A8_UNorm( texel[ 1 ], srcPtr[ 1 ] ); 408 | AddTexel( texel ); 409 | } 410 | } 411 | break; 412 | 413 | case DXGI_FORMAT_D16_UNORM: 414 | case DXGI_FORMAT_R16_UNORM: 415 | case DXGI_FORMAT_R16_UINT: 416 | case DXGI_FORMAT_R16_TYPELESS: 417 | case DXGI_FORMAT_R16_SNORM: 418 | case DXGI_FORMAT_R16_SINT: 419 | { 420 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 421 | { 422 | ReadD16_UNorm( texel[ 0 ], srcPtr[ 0 ] ); 423 | ReadD16_UNorm( texel[ 1 ], srcPtr[ 1 ] ); 424 | AddTexel( texel ); 425 | } 426 | } 427 | break; 428 | 429 | case DXGI_FORMAT_R10G10B10A2_TYPELESS: 430 | case DXGI_FORMAT_R10G10B10A2_UINT: 431 | case DXGI_FORMAT_R10G10B10A2_UNORM: 432 | { 433 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 434 | { 435 | ReadR10G10B10A2_UNorm( texel[ 0 ], srcPtr[ 0 ] ); 436 | ReadR10G10B10A2_UNorm( texel[ 1 ], srcPtr[ 1 ] ); 437 | AddTexel( texel ); 438 | } 439 | } 440 | break; 441 | 442 | case DXGI_FORMAT_R11G11B10_FLOAT: 443 | { 444 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 445 | { 446 | ReadR11G11B10_Float( texel[ 0 ], srcPtr[ 0 ] ); 447 | ReadR11G11B10_Float( texel[ 1 ], srcPtr[ 1 ] ); 448 | AddTexel( texel ); 449 | } 450 | } 451 | break; 452 | 453 | case DXGI_FORMAT_R16G16_FLOAT: 454 | { 455 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 456 | { 457 | ReadR16G16_Float( texel[ 0 ], srcPtr[ 0 ] ); 458 | ReadR16G16_Float( texel[ 1 ], srcPtr[ 1 ] ); 459 | AddTexel( texel ); 460 | } 461 | } 462 | break; 463 | 464 | case DXGI_FORMAT_R16G16B16A16_UINT: 465 | case DXGI_FORMAT_R16G16B16A16_UNORM: 466 | case DXGI_FORMAT_R16G16B16A16_TYPELESS: 467 | { 468 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 469 | { 470 | ReadR16G16B16A16_UNorm( texel[ 0 ], srcPtr[ 0 ] ); 471 | ReadR16G16B16A16_UNorm( texel[ 1 ], srcPtr[ 1 ] ); 472 | AddTexel( texel ); 473 | } 474 | } 475 | break; 476 | 477 | case DXGI_FORMAT_R16G16B16A16_FLOAT: 478 | { 479 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 480 | { 481 | ReadR16G16B16A16_Float( texel[ 0 ], srcPtr[ 0 ] ); 482 | ReadR16G16B16A16_Float( texel[ 1 ], srcPtr[ 1 ] ); 483 | AddTexel( texel ); 484 | } 485 | } 486 | break; 487 | 488 | case DXGI_FORMAT_R32G32B32_FLOAT: 489 | { 490 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 491 | { 492 | ReadR32G32B32_Float( texel[ 0 ], srcPtr[ 0 ] ); 493 | ReadR32G32B32_Float( texel[ 1 ], srcPtr[ 1 ] ); 494 | AddTexel( texel ); 495 | } 496 | } 497 | break; 498 | 499 | case DXGI_FORMAT_R32G32B32A32_FLOAT: 500 | { 501 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 502 | { 503 | ReadR32G32B32A32_Float( texel[ 0 ], srcPtr[ 0 ] ); 504 | ReadR32G32B32A32_Float( texel[ 1 ], srcPtr[ 1 ] ); 505 | AddTexel( texel ); 506 | } 507 | } 508 | break; 509 | 510 | case DXGI_FORMAT_R32G32B32A32_UINT: 511 | case DXGI_FORMAT_R32G32B32A32_TYPELESS: 512 | { 513 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 514 | { 515 | ReadR32G32B32A32_UInt( texel[ 0 ], srcPtr[ 0 ] ); 516 | ReadR32G32B32A32_UInt( texel[ 1 ], srcPtr[ 1 ] ); 517 | AddTexel( texel ); 518 | } 519 | } 520 | break; 521 | 522 | case DXGI_FORMAT_R32G32B32A32_SINT: 523 | { 524 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 525 | { 526 | ReadR32G32B32A32_SInt( texel[ 0 ], srcPtr[ 0 ] ); 527 | ReadR32G32B32A32_SInt( texel[ 1 ], srcPtr[ 1 ] ); 528 | AddTexel( texel ); 529 | } 530 | } 531 | break; 532 | 533 | case DXGI_FORMAT_R32_UINT: 534 | { 535 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 536 | { 537 | ReadR32_UInt( texel[ 0 ], srcPtr[ 0 ] ); 538 | ReadR32_UInt( texel[ 1 ], srcPtr[ 1 ] ); 539 | AddTexel( texel ); 540 | } 541 | } 542 | break; 543 | 544 | case DXGI_FORMAT_R32_SINT: 545 | { 546 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 547 | { 548 | ReadR32_SInt( texel[ 0 ], srcPtr[ 0 ] ); 549 | ReadR32_SInt( texel[ 1 ], srcPtr[ 1 ] ); 550 | AddTexel( texel ); 551 | } 552 | } 553 | break; 554 | 555 | case DXGI_FORMAT_D32_FLOAT: 556 | case DXGI_FORMAT_R32_FLOAT: 557 | case DXGI_FORMAT_R32_TYPELESS: 558 | { 559 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 560 | { 561 | ReadR32_Float( texel[ 0 ], srcPtr[ 0 ] ); 562 | ReadR32_Float( texel[ 1 ], srcPtr[ 1 ] ); 563 | AddTexel( texel ); 564 | } 565 | } 566 | break; 567 | 568 | case DXGI_FORMAT_R16_FLOAT: 569 | { 570 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 571 | { 572 | ReadR16_Float( texel[ 0 ], srcPtr[ 0 ] ); 573 | ReadR16_Float( texel[ 1 ], srcPtr[ 1 ] ); 574 | AddTexel( texel ); 575 | } 576 | } 577 | break; 578 | 579 | case DXGI_FORMAT_X24_TYPELESS_G8_UINT: 580 | case DXGI_FORMAT_R24G8_TYPELESS: 581 | { 582 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 583 | { 584 | ReadR24G8_UInt( texel[ 0 ], srcPtr[ 0 ] ); 585 | ReadR24G8_UInt( texel[ 1 ], srcPtr[ 1 ] ); 586 | AddTexel( texel ); 587 | } 588 | } 589 | break; 590 | 591 | case DXGI_FORMAT_R32G8X24_TYPELESS: 592 | case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: 593 | case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: 594 | { 595 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 596 | { 597 | ReadR32S8( texel[ 0 ], srcPtr[ 0 ] ); 598 | ReadR32S8( texel[ 1 ], srcPtr[ 1 ] ); 599 | AddTexel( texel ); 600 | } 601 | } 602 | break; 603 | } 604 | 605 | m_rmse = sqrtf( m_rmse / float( m_imageWidth * m_imageHeight ) ); 606 | 607 | QImage image0 = QImage( dataU8[ 0 ], m_imageWidth, m_imageHeight, m_imageWidth * 3, QImage::Format_RGB888 ); 608 | QImage image1 = QImage( dataU8[ 1 ], m_imageWidth, m_imageHeight, m_imageWidth * 3, QImage::Format_RGB888 ); 609 | QImage image2 = QImage( dataU8[ 2 ], m_imageWidth, m_imageHeight, m_imageWidth * 3, QImage::Format_RGB888 ); 610 | 611 | m_imageLabel[ 0 ].SetImage( image0 ); 612 | m_imageLabel[ 1 ].SetImage( image2 ); 613 | m_imageLabel[ 2 ].SetImage( image1 ); 614 | 615 | delete[] dataU8[ 0 ]; 616 | delete[] dataU8[ 1 ]; 617 | delete[] dataU8[ 2 ]; 618 | 619 | m_imageLabel[ 0 ].setFixedSize( m_imageWidth * m_zoom, m_imageHeight * m_zoom ); 620 | m_imageLabel[ 1 ].setFixedSize( m_imageWidth * m_zoom, m_imageHeight * m_zoom ); 621 | m_imageLabel[ 2 ].setFixedSize( m_imageWidth * m_zoom, m_imageHeight * m_zoom ); 622 | 623 | m_imageLabel[ 0 ].update(); 624 | m_imageLabel[ 1 ].update(); 625 | m_imageLabel[ 2 ].update(); 626 | m_gridLayout.update(); 627 | } 628 | 629 | void CCompareWindow::UpdateTitle() 630 | { 631 | m_title = QString( "%1 %2 rmse:%3 %4x%5 %6 mip:%7/%8 face:%9/%10 zoom:%11%" ) 632 | .arg( m_fileName[ 0 ] ) 633 | .arg( m_fileName[ 1 ] ) 634 | .arg( m_rmse ) 635 | .arg( m_info[ 0 ].width ) 636 | .arg( m_info[ 1 ].height ) 637 | .arg( m_formatName[ 0 ] ) 638 | .arg( m_viewMipMap ) 639 | .arg( m_info[ 1 ].mipLevels ) 640 | .arg( m_viewFace ) 641 | .arg( m_info[ 1 ].arraySize ) 642 | .arg( m_zoom * 100.0f ); 643 | 644 | extern CMainWindow* GMainWindow; 645 | GMainWindow->SetStatusLeft( m_title ); 646 | } 647 | 648 | bool CCompareWindow::eventFilter( QObject* object, QEvent* event ) 649 | { 650 | if ( event->type() == QEvent::Wheel ) 651 | { 652 | wheelEvent( (QWheelEvent*) event ); 653 | return true; 654 | } 655 | else if ( event->type() == QEvent::MouseMove ) 656 | { 657 | mouseMoveEvent( (QMouseEvent*) event ); 658 | return true; 659 | } 660 | else if ( event->type() == QEvent::MouseButtonPress ) 661 | { 662 | mousePressEvent( (QMouseEvent*) event ); 663 | return true; 664 | } 665 | else if ( event->type() == QEvent::MouseButtonRelease ) 666 | { 667 | mouseReleaseEvent( (QMouseEvent*) event ); 668 | return true; 669 | } 670 | 671 | return false; 672 | } 673 | 674 | void CCompareWindow::wheelEvent( QWheelEvent* event ) 675 | { 676 | float newZoom = m_zoom; 677 | if ( event->angleDelta().y() < 0 ) 678 | { 679 | newZoom *= 0.5f; 680 | } 681 | else 682 | { 683 | newZoom *= 2.0f; 684 | } 685 | newZoom = ClampZoom( newZoom ); 686 | 687 | if ( fabs( newZoom - m_zoom ) > 0.001f ) 688 | { 689 | float prevTexelX = ( event->x() + m_scrollBarH.value() - 0.5f ) / m_zoom; 690 | float prevTexelY = ( event->y() + m_scrollBarV.value() - 0.5f ) / m_zoom; 691 | 692 | m_zoom = newZoom; 693 | 694 | m_imageLabel[ 0 ].SetZoom( newZoom ); 695 | m_imageLabel[ 1 ].SetZoom( newZoom ); 696 | m_imageLabel[ 2 ].SetZoom( newZoom ); 697 | m_imageLabel[ 0 ].setFixedSize( m_imageWidth * newZoom, m_imageHeight * newZoom ); 698 | m_imageLabel[ 1 ].setFixedSize( m_imageWidth * newZoom, m_imageHeight * newZoom ); 699 | m_imageLabel[ 2 ].setFixedSize( m_imageWidth * newZoom, m_imageHeight * newZoom ); 700 | 701 | // scroll in order to hold to the same texel under the cursor after the zoom 702 | m_scrollBarH.setValue( prevTexelX * m_zoom - event->x() + 0.5f ); 703 | m_scrollBarV.setValue( prevTexelY * m_zoom - event->y() + 0.5f ); 704 | UpdateTitle(); 705 | } 706 | 707 | event->accept(); 708 | } 709 | 710 | void CCompareWindow::mousePressEvent( QMouseEvent* event ) 711 | { 712 | if ( event->buttons() & Qt::LeftButton ) 713 | { 714 | if ( event->modifiers() & Qt::ShiftModifier ) 715 | { 716 | m_selectionStart = event->pos(); 717 | m_selectionEnd = event->pos(); 718 | 719 | for ( unsigned i = 0; i < ARRAYSIZE( m_scrollArea ); ++i ) 720 | { 721 | if ( m_scrollArea[ i ].underMouse() ) 722 | { 723 | m_selection.setParent( &m_scrollArea[ i ] ); 724 | m_selection.move( m_selectionStart ); 725 | m_selection.resize( 0, 0 ); 726 | m_selection.show(); 727 | } 728 | } 729 | } 730 | else 731 | { 732 | m_dragEnabled = true; 733 | m_dragStart = QPoint( m_scrollBarH.value(), m_scrollBarV.value() ) + event->pos(); 734 | } 735 | } 736 | 737 | if ( event->buttons() & Qt::RightButton ) 738 | { 739 | PickTexel( event->pos() ); 740 | UpdateCrossCursor( event->pos() ); 741 | } 742 | } 743 | 744 | void CCompareWindow::mouseReleaseEvent( QMouseEvent* event ) 745 | { 746 | if ( event->button() == Qt::LeftButton ) 747 | { 748 | m_dragEnabled = false; 749 | 750 | if ( !m_selection.isHidden() ) 751 | { 752 | QPoint const selectionPos( qMin( m_selectionStart.x(), m_selectionEnd.x() ), qMin( m_selectionStart.y(), m_selectionEnd.y() ) ); 753 | QSize const selectionSize( abs( m_selectionStart.x() - m_selectionEnd.x() ), abs( m_selectionStart.y() - m_selectionEnd.y() ) ); 754 | QPoint const offset = QPoint( m_scrollBarH.value(), m_scrollBarV.value() ) + selectionPos; 755 | 756 | if ( selectionSize.width() > 0 && selectionSize.height() > 0 ) 757 | { 758 | float prevTexelX = ( offset.x() - 0.5f ) / m_zoom; 759 | float prevTexelY = ( offset.y() - 0.5f ) / m_zoom; 760 | 761 | QSize const viewport = ( (QScrollArea*) m_selection.parent() )->viewport()->size(); 762 | float const newZoom = ClampZoom( qMin( ( m_zoom * viewport.width() ) / selectionSize.width(), ( m_zoom * viewport.height() ) / selectionSize.height() ) ); 763 | 764 | m_zoom = newZoom; 765 | m_imageLabel[ 0 ].SetZoom( newZoom ); 766 | m_imageLabel[ 1 ].SetZoom( newZoom ); 767 | m_imageLabel[ 2 ].SetZoom( newZoom ); 768 | m_imageLabel[ 0 ].setFixedSize( m_imageWidth * newZoom, m_imageHeight * newZoom ); 769 | m_imageLabel[ 1 ].setFixedSize( m_imageWidth * newZoom, m_imageHeight * newZoom ); 770 | m_imageLabel[ 2 ].setFixedSize( m_imageWidth * newZoom, m_imageHeight * newZoom ); 771 | 772 | m_scrollBarH.setValue( prevTexelX * m_zoom + 0.5f ); 773 | m_scrollBarV.setValue( prevTexelY * m_zoom + 0.5f ); 774 | 775 | UpdateTitle(); 776 | } 777 | } 778 | 779 | m_selection.hide(); 780 | m_selectionStart = m_selectionEnd = QPoint( 0, 0 ); 781 | } 782 | 783 | if ( event->button() == Qt::RightButton ) 784 | { 785 | m_imageLabel[ 0 ].SetCrossPos( QPoint( -1, -1 ) ); 786 | m_imageLabel[ 1 ].SetCrossPos( QPoint( -1, -1 ) ); 787 | m_imageLabel[ 2 ].SetCrossPos( QPoint( -1, -1 ) ); 788 | } 789 | } 790 | 791 | void CCompareWindow::mouseMoveEvent( QMouseEvent* event ) 792 | { 793 | if ( !m_selection.isHidden() ) 794 | { 795 | m_selectionEnd = event->pos(); 796 | QPoint const selectionPos( qMin( m_selectionStart.x(), m_selectionEnd.x() ), qMin( m_selectionStart.y(), m_selectionEnd.y() ) ); 797 | QSize const selectionSize( abs( m_selectionStart.x() - m_selectionEnd.x() ), abs( m_selectionStart.y() - m_selectionEnd.y() ) ); 798 | 799 | m_selection.move( selectionPos ); 800 | m_selection.resize( selectionSize ); 801 | } 802 | 803 | if ( event->buttons() & Qt::LeftButton && m_dragEnabled ) 804 | { 805 | QPoint offset = m_dragStart - event->pos(); 806 | m_scrollBarH.setValue( offset.x() ); 807 | m_scrollBarV.setValue( offset.y() ); 808 | } 809 | 810 | if ( event->buttons() & Qt::RightButton ) 811 | { 812 | PickTexel( event->pos() ); 813 | UpdateCrossCursor( event->pos() ); 814 | } 815 | } 816 | 817 | void CCompareWindow::ScrollBarHRangeChanged( int min, int max ) 818 | { 819 | m_scrollBarH.setRange( m_scrollArea[ 0 ].horizontalScrollBar()->minimum(), m_scrollArea[ 0 ].horizontalScrollBar()->maximum() ); 820 | m_scrollBarH.setSingleStep( m_scrollArea[ 0 ].horizontalScrollBar()->singleStep() ); 821 | } 822 | 823 | void CCompareWindow::ScrollBarVRangeChanged( int min, int max ) 824 | { 825 | m_scrollBarV.setRange( m_scrollArea[ 0 ].verticalScrollBar()->minimum(), m_scrollArea[ 0 ].verticalScrollBar()->maximum() ); 826 | m_scrollBarV.setSingleStep( m_scrollArea[ 0 ].verticalScrollBar()->singleStep() ); 827 | } 828 | 829 | void CCompareWindow::ScrollBarHValueChanged( int value ) 830 | { 831 | m_scrollArea[ 0 ].horizontalScrollBar()->setValue( value ); 832 | m_scrollArea[ 1 ].horizontalScrollBar()->setValue( value ); 833 | m_scrollArea[ 2 ].horizontalScrollBar()->setValue( value ); 834 | } 835 | 836 | void CCompareWindow::ScrollBarVValueChanged( int value ) 837 | { 838 | m_scrollArea[ 0 ].verticalScrollBar()->setValue( value ); 839 | m_scrollArea[ 1 ].verticalScrollBar()->setValue( value ); 840 | m_scrollArea[ 2 ].verticalScrollBar()->setValue( value ); 841 | } 842 | 843 | void CCompareWindow::UpdateCrossCursor( QPoint const& cursorPos ) 844 | { 845 | QPoint const crossPos = cursorPos + QPoint( m_scrollBarH.value(), m_scrollBarV.value() ); 846 | m_imageLabel[ 0 ].SetCrossPos( m_scrollArea[ 0 ].underMouse() ? QPoint( -1, -1 ) : crossPos ); 847 | m_imageLabel[ 1 ].SetCrossPos( m_scrollArea[ 1 ].underMouse() ? QPoint( -1, -1 ) : crossPos ); 848 | m_imageLabel[ 2 ].SetCrossPos( m_scrollArea[ 2 ].underMouse() ? QPoint( -1, -1 ) : crossPos ); 849 | } 850 | 851 | void CCompareWindow::PickTexel( QPoint const& pos ) 852 | { 853 | unsigned texelX = ClampF( ( pos.x() + m_scrollBarH.value() - 0.5f ) / m_zoom, 0.0f, m_imageWidth - 1.0f ); 854 | unsigned texelY = ClampF( ( pos.y() + m_scrollBarV.value() - 0.5f ) / m_zoom, 0.0f, m_imageHeight - 1.0f ); 855 | 856 | QString texelInfo0[ 4 ]; 857 | QString texelInfo1[ 4 ]; 858 | if ( texelX >= 0 && texelX < m_imageWidth && texelY >= 0 && texelY < m_imageHeight ) 859 | { 860 | DirectX::Image const* img0 = m_scratchImage[ 0 ].GetImage( m_viewMipMap, m_viewFace, 0 ); 861 | DirectX::Image const* img1 = m_scratchImage[ 1 ].GetImage( m_viewMipMap, m_viewFace, 0 ); 862 | uint8_t* src0Ptr = img0->pixels + m_texelSizeInBytes * ( texelX + texelY * m_imageWidth ); 863 | uint8_t* src1Ptr = img1->pixels + m_texelSizeInBytes * ( texelX + texelY * m_imageWidth ); 864 | 865 | switch ( m_info[ 0 ].format ) 866 | { 867 | case DXGI_FORMAT_R8_TYPELESS: 868 | case DXGI_FORMAT_R8_UNORM: 869 | case DXGI_FORMAT_R8_UINT: 870 | case DXGI_FORMAT_R8_SNORM: 871 | case DXGI_FORMAT_R8_SINT: 872 | { 873 | TexelInfoR8_UNorm( texelInfo0, src0Ptr ); 874 | TexelInfoR8_UNorm( texelInfo1, src1Ptr ); 875 | } 876 | break; 877 | 878 | case DXGI_FORMAT_R8G8_SNORM: 879 | case DXGI_FORMAT_R8G8_SINT: 880 | { 881 | TexelInfoR8G8_SNorm( texelInfo0, src0Ptr ); 882 | TexelInfoR8G8_SNorm( texelInfo1, src1Ptr ); 883 | } 884 | break; 885 | 886 | case DXGI_FORMAT_R8G8_UNORM: 887 | case DXGI_FORMAT_R8G8_UINT: 888 | case DXGI_FORMAT_R8G8_TYPELESS: 889 | { 890 | TexelInfoR8G8_UNorm( texelInfo0, src0Ptr ); 891 | TexelInfoR8G8_UNorm( texelInfo1, src1Ptr ); 892 | } 893 | break; 894 | 895 | case DXGI_FORMAT_X24_TYPELESS_G8_UINT: 896 | case DXGI_FORMAT_R24G8_TYPELESS: 897 | { 898 | TexelInfoR24G8_UInt( texelInfo0, src0Ptr ); 899 | TexelInfoR24G8_UInt( texelInfo1, src1Ptr ); 900 | } 901 | break; 902 | 903 | case DXGI_FORMAT_B8G8R8X8_UNORM: 904 | case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: 905 | { 906 | TexelInfoB8G8R8X8_UNorm( texelInfo0, src0Ptr ); 907 | TexelInfoB8G8R8X8_UNorm( texelInfo1, src1Ptr ); 908 | } 909 | break; 910 | 911 | case DXGI_FORMAT_B8G8R8A8_UNORM: 912 | case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: 913 | { 914 | TexelInfoB8G8R8A8_UNorm( texelInfo0, src0Ptr ); 915 | TexelInfoB8G8R8A8_UNorm( texelInfo1, src1Ptr ); 916 | } 917 | break; 918 | 919 | case DXGI_FORMAT_R10G10B10A2_TYPELESS: 920 | case DXGI_FORMAT_R10G10B10A2_UINT: 921 | case DXGI_FORMAT_R10G10B10A2_UNORM: 922 | { 923 | TexelInfoR10G10B10A2_UNorm( texelInfo0, src0Ptr ); 924 | TexelInfoR10G10B10A2_UNorm( texelInfo1, src1Ptr ); 925 | } 926 | break; 927 | 928 | case DXGI_FORMAT_R8G8B8A8_TYPELESS: 929 | case DXGI_FORMAT_R8G8B8A8_UINT: 930 | case DXGI_FORMAT_R8G8B8A8_UNORM: 931 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: 932 | { 933 | TexelInfoR8G8B8A8_UNorm( texelInfo0, src0Ptr ); 934 | TexelInfoR8G8B8A8_UNorm( texelInfo1, src1Ptr ); 935 | } 936 | break; 937 | 938 | case DXGI_FORMAT_R11G11B10_FLOAT: 939 | { 940 | TexelInfoR11G11B10_Float( texelInfo0, src0Ptr ); 941 | TexelInfoR11G11B10_Float( texelInfo1, src1Ptr ); 942 | } 943 | break; 944 | 945 | case DXGI_FORMAT_R16G16_FLOAT: 946 | { 947 | TexelInfoR16G16_Float( texelInfo0, src0Ptr ); 948 | TexelInfoR16G16_Float( texelInfo1, src1Ptr ); 949 | } 950 | break; 951 | 952 | case DXGI_FORMAT_R16G16B16A16_UINT: 953 | case DXGI_FORMAT_R16G16B16A16_UNORM: 954 | case DXGI_FORMAT_R16G16B16A16_TYPELESS: 955 | { 956 | TexelInfoR16G16B16A16_UNorm( texelInfo0, src0Ptr ); 957 | TexelInfoR16G16B16A16_UNorm( texelInfo1, src1Ptr ); 958 | } 959 | break; 960 | 961 | case DXGI_FORMAT_R16G16B16A16_FLOAT: 962 | { 963 | TexelInfoR16G16B16A16_Float( texelInfo0, src0Ptr ); 964 | TexelInfoR16G16B16A16_Float( texelInfo1, src1Ptr ); 965 | } 966 | break; 967 | 968 | case DXGI_FORMAT_R32G32B32_FLOAT: 969 | { 970 | TexelInfoR32G32B32_Float( texelInfo0, src0Ptr ); 971 | TexelInfoR32G32B32_Float( texelInfo1, src1Ptr ); 972 | } 973 | break; 974 | 975 | case DXGI_FORMAT_R32G32B32A32_FLOAT: 976 | { 977 | TexelInfoR32G32B32A32_Float( texelInfo0, src0Ptr ); 978 | TexelInfoR32G32B32A32_Float( texelInfo1, src1Ptr ); 979 | } 980 | break; 981 | 982 | case DXGI_FORMAT_R32G32B32A32_UINT: 983 | case DXGI_FORMAT_R32G32B32A32_TYPELESS: 984 | { 985 | TexelInfoR32G32B32A32_UInt( texelInfo0, src0Ptr ); 986 | TexelInfoR32G32B32A32_UInt( texelInfo1, src1Ptr ); 987 | } 988 | break; 989 | 990 | case DXGI_FORMAT_R32G32B32A32_SINT: 991 | { 992 | TexelInfoR32G32B32A32_SInt( texelInfo0, src0Ptr ); 993 | TexelInfoR32G32B32A32_SInt( texelInfo1, src1Ptr ); 994 | } 995 | break; 996 | 997 | case DXGI_FORMAT_R32_UINT: 998 | { 999 | TexelInfoR32_UInt( texelInfo0, src0Ptr ); 1000 | TexelInfoR32_UInt( texelInfo1, src1Ptr ); 1001 | } 1002 | break; 1003 | 1004 | case DXGI_FORMAT_R32_SINT: 1005 | { 1006 | TexelInfoR32_SInt( texelInfo0, src0Ptr ); 1007 | TexelInfoR32_SInt( texelInfo1, src1Ptr ); 1008 | } 1009 | break; 1010 | 1011 | case DXGI_FORMAT_D32_FLOAT: 1012 | case DXGI_FORMAT_R32_FLOAT: 1013 | case DXGI_FORMAT_R32_TYPELESS: 1014 | { 1015 | TexelInfoR32_Float( texelInfo0, src0Ptr ); 1016 | TexelInfoR32_Float( texelInfo1, src1Ptr ); 1017 | } 1018 | break; 1019 | 1020 | case DXGI_FORMAT_R16_FLOAT: 1021 | { 1022 | TexelInfoR16_Float( texelInfo0, src0Ptr ); 1023 | TexelInfoR16_Float( texelInfo1, src1Ptr ); 1024 | } 1025 | break; 1026 | 1027 | case DXGI_FORMAT_D16_UNORM: 1028 | case DXGI_FORMAT_R16_UNORM: 1029 | case DXGI_FORMAT_R16_UINT: 1030 | case DXGI_FORMAT_R16_TYPELESS: 1031 | case DXGI_FORMAT_R16_SNORM: 1032 | case DXGI_FORMAT_R16_SINT: 1033 | { 1034 | TexelInfoD16_UNorm( texelInfo0, src0Ptr ); 1035 | TexelInfoD16_UNorm( texelInfo1, src1Ptr ); 1036 | } 1037 | break; 1038 | 1039 | case DXGI_FORMAT_R32G8X24_TYPELESS: 1040 | case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: 1041 | case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: 1042 | { 1043 | TexelInfoR32S8( texelInfo0, src0Ptr ); 1044 | TexelInfoR32S8( texelInfo1, src1Ptr ); 1045 | } 1046 | break; 1047 | } 1048 | } 1049 | 1050 | 1051 | QString texelDesc = QString::number( texelX ) + "x" + QString::number( texelY ); 1052 | QString tooltip = texelDesc; 1053 | 1054 | QString const channelNames[ 4 ] = { "R:", "G:", "B:", "A:" }; 1055 | for ( unsigned i = 0; i < 4; ++i ) 1056 | { 1057 | if ( !texelInfo0[ i ].isEmpty() ) 1058 | { 1059 | texelDesc += " " + channelNames[ i ] + texelInfo0[ i ]; 1060 | } 1061 | } 1062 | texelDesc += " ##"; 1063 | for ( unsigned i = 0; i < 4; ++i ) 1064 | { 1065 | if ( !texelInfo1[ i ].isEmpty() ) 1066 | { 1067 | texelDesc += " " + channelNames[ i ] + texelInfo1[ i ]; 1068 | } 1069 | } 1070 | 1071 | for ( unsigned i = 0; i < 4; ++i ) 1072 | { 1073 | if ( !texelInfo0[ i ].isEmpty() ) 1074 | { 1075 | tooltip += "\n" + channelNames[ i ] + texelInfo0[ i ] + " # " +texelInfo1[ i ]; 1076 | } 1077 | } 1078 | 1079 | extern CMainWindow* GMainWindow; 1080 | GMainWindow->SetStatusRight( texelDesc ); 1081 | QToolTip::showText( QCursor::pos(), tooltip ); 1082 | } -------------------------------------------------------------------------------- /compareWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "baseWindow.h" 4 | 5 | class CCompareImageLabel : public QLabel 6 | { 7 | Q_OBJECT 8 | 9 | public: 10 | CCompareImageLabel(); 11 | void SetZoom( float zoom ); 12 | void SetImage( QImage const& image ); 13 | void SetCrossPos( QPoint const& pos ); 14 | 15 | 16 | private: 17 | QPixmap m_pixmap; 18 | QPixmap m_crossPixmap; 19 | QPoint m_crossPos; 20 | float m_zoom; 21 | 22 | void paintEvent( QPaintEvent* event ) Q_DECL_OVERRIDE; 23 | }; 24 | 25 | class CCompareWindow : public QWidget, public CBaseWindow 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | CCompareWindow(); 31 | ~CCompareWindow(); 32 | bool LoadFiles( QString const& path0, QString const& path1 ); 33 | virtual void Reload(); 34 | virtual void ZoomIn(); 35 | virtual void ZoomOut(); 36 | virtual void SetViewChannel( EViewChannel channel ); 37 | virtual void SetViewFace( unsigned face ); 38 | virtual void SetViewMipMap( unsigned mipMap ); 39 | virtual void SetViewMin( float min ); 40 | virtual void SetViewMax( float max ); 41 | virtual void SetViewGamma( float gamma ); 42 | virtual void SetViewDiffMult( float mult ); 43 | virtual QSize GetInitialSize() const { return QSize( m_imageWidth, m_imageHeight ); } 44 | virtual QString const& GetTitle() const { return m_title; } 45 | virtual EViewChannel GetViewChannel() const { return m_viewChannel; } 46 | virtual unsigned GetMipNum() const { return m_info[ 0 ].mipLevels; } 47 | virtual unsigned GetFaceNum() const { return m_info[ 0 ].arraySize; } 48 | virtual unsigned GetViewFace() const { return m_viewFace; } 49 | virtual unsigned GetViewMipMap() const { return m_viewMipMap; } 50 | virtual float GetViewMin() const { return m_viewMin; } 51 | virtual float GetViewMax() const { return m_viewMax; } 52 | virtual float GetViewGamma() const { return m_viewGamma; } 53 | virtual float GetViewDiffMult() const { return m_viewDiffMult; } 54 | 55 | private slots: 56 | void ScrollBarHRangeChanged( int min, int max ); 57 | void ScrollBarVRangeChanged( int min, int max ); 58 | void ScrollBarHValueChanged( int value ); 59 | void ScrollBarVValueChanged( int value ); 60 | 61 | private: 62 | QString m_title; 63 | DirectX::ScratchImage m_scratchImage[ 2 ]; 64 | DirectX::TexMetadata m_info[ 2 ]; 65 | QString m_path[ 2 ]; 66 | QString m_fileName[ 2 ]; 67 | QString m_formatName[ 2 ]; 68 | QGridLayout m_gridLayout; 69 | QScrollArea m_scrollArea[ 3 ]; 70 | CCompareImageLabel m_imageLabel[ 3 ]; 71 | QScrollBar m_scrollBarH; 72 | QScrollBar m_scrollBarV; 73 | float m_rmse; 74 | float m_zoom; 75 | bool m_dragEnabled; 76 | QPoint m_dragStart; 77 | EViewChannel m_viewChannel; 78 | unsigned m_texelSizeInBytes; 79 | unsigned m_viewFace; 80 | unsigned m_viewMipMap; 81 | float m_viewMin; 82 | float m_viewMax; 83 | float m_viewGamma; 84 | float m_viewDiffMult; 85 | unsigned m_imageWidth; 86 | unsigned m_imageHeight; 87 | 88 | QPoint m_selectionStart; 89 | QPoint m_selectionEnd; 90 | QRubberBand m_selection; 91 | 92 | void mousePressEvent( QMouseEvent* event ) Q_DECL_OVERRIDE; 93 | void mouseReleaseEvent( QMouseEvent* event ) Q_DECL_OVERRIDE; 94 | void mouseMoveEvent( QMouseEvent* event ) Q_DECL_OVERRIDE; 95 | void wheelEvent( QWheelEvent* event ) Q_DECL_OVERRIDE; 96 | bool eventFilter( QObject* object, QEvent* event ) Q_DECL_OVERRIDE; 97 | void UpdateImage(); 98 | void PickTexel( QPoint const& pos ); 99 | void UpdateCrossCursor( QPoint const& cursorPos ); 100 | void UpdateTitle(); 101 | }; -------------------------------------------------------------------------------- /imageWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "imageWindow.h" 3 | #include "mainWindow.h" 4 | #include "util.h" 5 | 6 | CImageWindow::CImageWindow() 7 | : m_zoom( 1.0f ) 8 | , m_viewChannel( EViewChannel::RGB ) 9 | , m_viewFace( 0 ) 10 | , m_viewMipMap( 0 ) 11 | , m_imageWidth( 0 ) 12 | , m_imageHeight( 0 ) 13 | , m_viewMin( 0.0f ) 14 | , m_viewMax( 1.0f ) 15 | , m_viewGamma( 1.0f ) 16 | , m_dragEnabled( false ) 17 | , m_selection( QRubberBand::Shape::Rectangle, this ) 18 | { 19 | memset( &m_info, 0, sizeof( m_info ) ); 20 | 21 | setAttribute( Qt::WA_DeleteOnClose ); 22 | setWidget( &m_imageLabel ); 23 | } 24 | 25 | bool CImageWindow::LoadFile( QString const& path ) 26 | { 27 | m_path = path; 28 | if ( !UtilLoadFile( m_scratchImage, m_info, m_formatName, m_fileName, m_texelSizeInBytes, path ) ) 29 | { 30 | memset( &m_info, 0, sizeof( m_info ) ); 31 | return false; 32 | } 33 | 34 | ( (QMdiSubWindow*) parentWidget() )->setWindowTitle( path ); 35 | UpdateTitle(); 36 | UpdateImage(); 37 | return true; 38 | } 39 | 40 | void CImageWindow::Reload() 41 | { 42 | LoadFile( m_path ); 43 | } 44 | 45 | void CImageWindow::ZoomIn() 46 | { 47 | QWheelEvent event( QPointF( 0.0f, 0.0f ), 1, Qt::MouseButton::NoButton, 0 ); 48 | wheelEvent( &event ); 49 | } 50 | 51 | void CImageWindow::ZoomOut() 52 | { 53 | QWheelEvent event( QPointF( 0.0f, 0.0f ), -1, Qt::MouseButton::NoButton, 0 ); 54 | wheelEvent( &event ); 55 | } 56 | 57 | void CImageWindow::UpdateTitle() 58 | { 59 | m_title = QString( "%1 %2x%3 %4 mip:%5/%6 face:%7/%8 zoom:%9%" ) 60 | .arg( m_fileName ) 61 | .arg( m_info.width ) 62 | .arg( m_info.height ) 63 | .arg( m_formatName ) 64 | .arg( m_viewMipMap ) 65 | .arg( m_info.mipLevels ) 66 | .arg( m_viewFace ) 67 | .arg( m_info.arraySize ) 68 | .arg( m_zoom * 100.0f ); 69 | 70 | extern CMainWindow* GMainWindow; 71 | GMainWindow->SetStatusLeft( m_title ); 72 | } 73 | 74 | void CImageWindow::SetViewChannel( EViewChannel channel ) 75 | { 76 | if ( m_viewChannel != channel ) 77 | { 78 | m_viewChannel = channel; 79 | UpdateImage(); 80 | UpdateTitle(); 81 | } 82 | } 83 | 84 | void CImageWindow::SetViewFace( unsigned face ) 85 | { 86 | if ( m_viewFace != face ) 87 | { 88 | m_viewFace = face; 89 | UpdateImage(); 90 | UpdateTitle(); 91 | } 92 | } 93 | 94 | void CImageWindow::SetViewMipMap( unsigned mipMap ) 95 | { 96 | if ( m_viewMipMap != mipMap ) 97 | { 98 | m_viewMipMap = mipMap; 99 | UpdateImage(); 100 | UpdateTitle(); 101 | } 102 | } 103 | 104 | void CImageWindow::SetViewMin( float min ) 105 | { 106 | if ( m_viewMin != min ) 107 | { 108 | m_viewMin = min; 109 | UpdateImage(); 110 | } 111 | } 112 | 113 | void CImageWindow::SetViewMax( float max ) 114 | { 115 | if ( m_viewMax != max ) 116 | { 117 | m_viewMax = max; 118 | UpdateImage(); 119 | } 120 | } 121 | 122 | void CImageWindow::SetViewGamma( float gamma ) 123 | { 124 | if ( m_viewGamma != gamma ) 125 | { 126 | m_viewGamma = gamma; 127 | UpdateImage(); 128 | } 129 | } 130 | 131 | void CImageWindow::UpdateImage() 132 | { 133 | m_viewFace = std::min( m_viewFace, m_info.arraySize - 1 ); 134 | m_viewMipMap = std::min( m_viewMipMap, m_info.mipLevels - 1 ); 135 | 136 | DirectX::Image const* img = m_scratchImage.GetImage( m_viewMipMap, m_viewFace, 0 ); 137 | uint8_t* srcPtr = img->pixels; 138 | m_imageWidth = img->width; 139 | m_imageHeight = img->height; 140 | 141 | unsigned redIdx = 0; 142 | unsigned greenIdx = 1; 143 | unsigned blueIdx = 2; 144 | switch ( m_viewChannel ) 145 | { 146 | case EViewChannel::R: redIdx = greenIdx = blueIdx = 0; break; 147 | case EViewChannel::G: redIdx = greenIdx = blueIdx = 1; break; 148 | case EViewChannel::B: redIdx = greenIdx = blueIdx = 2; break; 149 | case EViewChannel::A: redIdx = greenIdx = blueIdx = 3; break; 150 | } 151 | 152 | float const viewScale = 1.0f / ( m_viewMax - m_viewMin ); 153 | uint8_t* dataU8 = new uint8_t[ m_imageWidth * m_imageHeight * 4 ]; 154 | uint8_t* dataPtr = dataU8; 155 | 156 | auto AddTexel = [&]( float texel[ 4 ] ) 157 | { 158 | texel[ 0 ] = powf( ( texel[ 0 ] - m_viewMin ) * viewScale, m_viewGamma ); 159 | texel[ 1 ] = powf( ( texel[ 1 ] - m_viewMin ) * viewScale, m_viewGamma ); 160 | texel[ 2 ] = powf( ( texel[ 2 ] - m_viewMin ) * viewScale, m_viewGamma ); 161 | texel[ 3 ] = powf( ( texel[ 3 ] - m_viewMin ) * viewScale, m_viewGamma ); 162 | 163 | dataPtr[ 0 ] = (uint8_t) ClampF( texel[ redIdx ] * 255.0f + 0.5f, 0.0f, 255.0f ); 164 | dataPtr[ 1 ] = (uint8_t) ClampF( texel[ greenIdx ] * 255.0f + 0.5f, 0.0f, 255.0f ); 165 | dataPtr[ 2 ] = (uint8_t) ClampF( texel[ blueIdx ] * 255.0f + 0.5f, 0.0f, 255.0f ); 166 | dataPtr += 3; 167 | }; 168 | 169 | float texel[ 4 ]; 170 | switch ( m_info.format ) 171 | { 172 | case DXGI_FORMAT_R8_TYPELESS: 173 | case DXGI_FORMAT_R8_UNORM: 174 | case DXGI_FORMAT_R8_UINT: 175 | case DXGI_FORMAT_R8_SNORM: 176 | case DXGI_FORMAT_R8_SINT: 177 | { 178 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 179 | { 180 | ReadR8_UNorm( texel, srcPtr ); 181 | AddTexel( texel ); 182 | } 183 | } 184 | break; 185 | 186 | case DXGI_FORMAT_R8G8_SNORM: 187 | case DXGI_FORMAT_R8G8_SINT: 188 | { 189 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 190 | { 191 | ReadR8G8_UNorm( texel, srcPtr ); 192 | AddTexel( texel ); 193 | } 194 | } 195 | break; 196 | 197 | case DXGI_FORMAT_R8G8_UNORM: 198 | case DXGI_FORMAT_R8G8_UINT: 199 | case DXGI_FORMAT_R8G8_TYPELESS: 200 | { 201 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 202 | { 203 | ReadR8G8_UNorm( texel, srcPtr ); 204 | AddTexel( texel ); 205 | } 206 | } 207 | break; 208 | 209 | case DXGI_FORMAT_B8G8R8A8_UNORM: 210 | case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: 211 | { 212 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 213 | { 214 | ReadB8G8R8A8_UNorm( texel, srcPtr ); 215 | AddTexel( texel ); 216 | } 217 | } 218 | break; 219 | 220 | case DXGI_FORMAT_B8G8R8X8_UNORM: 221 | case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: 222 | { 223 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 224 | { 225 | ReadB8G8R8X8_UNorm( texel, srcPtr ); 226 | AddTexel( texel ); 227 | } 228 | } 229 | break; 230 | 231 | case DXGI_FORMAT_R8G8B8A8_TYPELESS: 232 | case DXGI_FORMAT_R8G8B8A8_UINT: 233 | case DXGI_FORMAT_R8G8B8A8_UNORM: 234 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: 235 | { 236 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 237 | { 238 | ReadR8G8B8A8_UNorm( texel, srcPtr ); 239 | AddTexel( texel ); 240 | } 241 | } 242 | break; 243 | 244 | case DXGI_FORMAT_D16_UNORM: 245 | case DXGI_FORMAT_R16_UNORM: 246 | case DXGI_FORMAT_R16_UINT: 247 | case DXGI_FORMAT_R16_TYPELESS: 248 | case DXGI_FORMAT_R16_SNORM: 249 | case DXGI_FORMAT_R16_SINT: 250 | { 251 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 252 | { 253 | ReadD16_UNorm( texel, srcPtr ); 254 | AddTexel( texel ); 255 | } 256 | } 257 | break; 258 | 259 | case DXGI_FORMAT_R10G10B10A2_TYPELESS: 260 | case DXGI_FORMAT_R10G10B10A2_UINT: 261 | case DXGI_FORMAT_R10G10B10A2_UNORM: 262 | { 263 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 264 | { 265 | ReadR10G10B10A2_UNorm( texel, srcPtr ); 266 | AddTexel( texel ); 267 | } 268 | } 269 | break; 270 | 271 | case DXGI_FORMAT_R11G11B10_FLOAT: 272 | { 273 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 274 | { 275 | ReadR11G11B10_Float( texel, srcPtr ); 276 | AddTexel( texel ); 277 | } 278 | } 279 | break; 280 | 281 | case DXGI_FORMAT_R16G16_FLOAT: 282 | { 283 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 284 | { 285 | ReadR16G16_Float( texel, srcPtr ); 286 | AddTexel( texel ); 287 | } 288 | } 289 | break; 290 | 291 | case DXGI_FORMAT_R16G16B16A16_UINT: 292 | case DXGI_FORMAT_R16G16B16A16_UNORM: 293 | case DXGI_FORMAT_R16G16B16A16_TYPELESS: 294 | { 295 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 296 | { 297 | ReadR16G16B16A16_UNorm( texel, srcPtr ); 298 | AddTexel( texel ); 299 | } 300 | } 301 | break; 302 | 303 | case DXGI_FORMAT_R16G16B16A16_FLOAT: 304 | { 305 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 306 | { 307 | ReadR16G16B16A16_Float( texel, srcPtr ); 308 | AddTexel( texel ); 309 | } 310 | } 311 | break; 312 | 313 | case DXGI_FORMAT_R32G32B32_FLOAT: 314 | { 315 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 316 | { 317 | ReadR32G32B32_Float( texel, srcPtr ); 318 | AddTexel( texel ); 319 | } 320 | } 321 | break; 322 | 323 | case DXGI_FORMAT_R32G32B32A32_FLOAT: 324 | { 325 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 326 | { 327 | ReadR32G32B32A32_Float( texel, srcPtr ); 328 | AddTexel( texel ); 329 | } 330 | } 331 | break; 332 | 333 | case DXGI_FORMAT_R32G32B32A32_UINT: 334 | case DXGI_FORMAT_R32G32B32A32_TYPELESS: 335 | { 336 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 337 | { 338 | ReadR32G32B32A32_UInt( texel, srcPtr ); 339 | AddTexel( texel ); 340 | } 341 | } 342 | break; 343 | 344 | case DXGI_FORMAT_R32G32B32A32_SINT: 345 | { 346 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 347 | { 348 | ReadR32G32B32A32_SInt( texel, srcPtr ); 349 | AddTexel( texel ); 350 | } 351 | } 352 | break; 353 | 354 | case DXGI_FORMAT_R32_UINT: 355 | { 356 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 357 | { 358 | ReadR32_UInt( texel, srcPtr ); 359 | AddTexel( texel ); 360 | } 361 | } 362 | break; 363 | 364 | case DXGI_FORMAT_R32_SINT: 365 | { 366 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 367 | { 368 | ReadR32_SInt( texel, srcPtr ); 369 | AddTexel( texel ); 370 | } 371 | } 372 | break; 373 | 374 | case DXGI_FORMAT_D32_FLOAT: 375 | case DXGI_FORMAT_R32_FLOAT: 376 | case DXGI_FORMAT_R32_TYPELESS: 377 | { 378 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 379 | { 380 | ReadR32_Float( texel, srcPtr ); 381 | AddTexel( texel ); 382 | } 383 | } 384 | break; 385 | 386 | case DXGI_FORMAT_R16_FLOAT: 387 | { 388 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 389 | { 390 | ReadR16_Float( texel, srcPtr ); 391 | AddTexel( texel ); 392 | } 393 | } 394 | break; 395 | 396 | case DXGI_FORMAT_X24_TYPELESS_G8_UINT: 397 | case DXGI_FORMAT_R24G8_TYPELESS: 398 | { 399 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 400 | { 401 | ReadR24G8_UInt( texel, srcPtr ); 402 | AddTexel( texel ); 403 | } 404 | } 405 | break; 406 | 407 | case DXGI_FORMAT_R32G8X24_TYPELESS: 408 | case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: 409 | case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: 410 | { 411 | for ( unsigned iTexel = 0; iTexel < m_imageWidth * m_imageHeight; ++iTexel ) 412 | { 413 | ReadR32S8( texel, srcPtr ); 414 | AddTexel( texel ); 415 | } 416 | } 417 | break; 418 | } 419 | 420 | QImage image = QImage( dataU8, m_imageWidth, m_imageHeight, m_imageWidth * 3, QImage::Format_RGB888 ); 421 | m_imageLabel.SetImage( image ); 422 | delete[] dataU8; 423 | 424 | m_imageLabel.setFixedSize( m_imageWidth * m_zoom, m_imageHeight * m_zoom ); 425 | m_imageLabel.update(); 426 | } 427 | 428 | void CImageWindow::mousePressEvent( QMouseEvent* event ) 429 | { 430 | if ( event->buttons() & Qt::LeftButton ) 431 | { 432 | if ( event->modifiers() & Qt::ShiftModifier ) 433 | { 434 | m_selectionStart = event->pos(); 435 | m_selectionEnd = event->pos(); 436 | m_selection.move( m_selectionStart ); 437 | m_selection.resize( 0, 0 ); 438 | m_selection.show(); 439 | } 440 | else 441 | { 442 | m_dragEnabled = true; 443 | m_dragStart = QPoint( horizontalScrollBar()->value(), verticalScrollBar()->value() ) + event->pos(); 444 | } 445 | } 446 | 447 | if ( event->buttons() & Qt::RightButton ) 448 | { 449 | PickTexel( event->pos() ); 450 | } 451 | } 452 | 453 | void CImageWindow::mouseReleaseEvent( QMouseEvent* event ) 454 | { 455 | if ( event->button() == Qt::LeftButton ) 456 | { 457 | m_dragEnabled = false; 458 | 459 | if ( !m_selection.isHidden() ) 460 | { 461 | QPoint const selectionPos( qMin( m_selectionStart.x(), m_selectionEnd.x() ), qMin( m_selectionStart.y(), m_selectionEnd.y() ) ); 462 | QSize const selectionSize( abs( m_selectionStart.x() - m_selectionEnd.x() ), abs( m_selectionStart.y() - m_selectionEnd.y() ) ); 463 | QPoint const offset = QPoint( horizontalScrollBar()->value(), verticalScrollBar()->value() ) + selectionPos; 464 | 465 | if ( selectionSize.width() > 0 && selectionSize.height() > 0 ) 466 | { 467 | float prevTexelX = ( offset.x() - 0.5f ) / m_zoom; 468 | float prevTexelY = ( offset.y() - 0.5f ) / m_zoom; 469 | 470 | float const newZoom = ClampZoom( qMin( ( m_zoom * viewport()->width() ) / selectionSize.width(), ( m_zoom * viewport()->height() ) / selectionSize.height() ) ); 471 | 472 | m_zoom = newZoom; 473 | m_imageLabel.SetZoom( newZoom ); 474 | m_imageLabel.setFixedSize( m_imageWidth * newZoom, m_imageHeight * newZoom ); 475 | 476 | horizontalScrollBar()->setValue( prevTexelX * m_zoom + 0.5f ); 477 | verticalScrollBar()->setValue( prevTexelY * m_zoom + 0.5f ); 478 | 479 | UpdateTitle(); 480 | } 481 | } 482 | 483 | m_selection.hide(); 484 | m_selectionStart = m_selectionEnd = QPoint( 0, 0 ); 485 | } 486 | } 487 | 488 | void CImageWindow::mouseMoveEvent( QMouseEvent* event ) 489 | { 490 | if ( !m_selection.isHidden() ) 491 | { 492 | m_selectionEnd = event->pos(); 493 | QPoint const selectionPos( qMin( m_selectionStart.x(), m_selectionEnd.x() ), qMin( m_selectionStart.y(), m_selectionEnd.y() ) ); 494 | QSize const selectionSize( abs( m_selectionStart.x() - m_selectionEnd.x() ), abs( m_selectionStart.y() - m_selectionEnd.y() ) ); 495 | 496 | m_selection.move( selectionPos ); 497 | m_selection.resize( selectionSize ); 498 | } 499 | 500 | if ( event->buttons() & Qt::LeftButton && m_dragEnabled ) 501 | { 502 | QPoint offset = m_dragStart - event->pos(); 503 | horizontalScrollBar()->setValue( offset.x() ); 504 | verticalScrollBar()->setValue( offset.y() ); 505 | } 506 | 507 | if ( event->buttons() & Qt::RightButton ) 508 | { 509 | PickTexel( event->pos() ); 510 | } 511 | } 512 | 513 | void CImageWindow::PickTexel( QPoint const& pos ) 514 | { 515 | unsigned texelX = ClampF( ( pos.x() + horizontalScrollBar()->value() - 0.5f ) / m_zoom, 0.0f, m_imageWidth - 1.0f ); 516 | unsigned texelY = ClampF( ( pos.y() + verticalScrollBar()->value() - 0.5f ) / m_zoom, 0.0f, m_imageHeight - 1.0f ); 517 | 518 | QString texelInfo[ 4 ]; 519 | if ( texelX >= 0 && texelX < m_imageWidth && texelY >= 0 && texelY < m_imageHeight ) 520 | { 521 | DirectX::Image const* img = m_scratchImage.GetImage( m_viewMipMap, m_viewFace, 0 ); 522 | uint8_t* srcPtr = img->pixels + m_texelSizeInBytes * ( texelX + texelY * m_imageWidth ); 523 | 524 | switch ( m_info.format ) 525 | { 526 | case DXGI_FORMAT_R8_TYPELESS: 527 | case DXGI_FORMAT_R8_UNORM: 528 | case DXGI_FORMAT_R8_UINT: 529 | case DXGI_FORMAT_R8_SNORM: 530 | case DXGI_FORMAT_R8_SINT: 531 | { 532 | TexelInfoR8_UNorm( texelInfo, srcPtr ); 533 | } 534 | break; 535 | 536 | case DXGI_FORMAT_R8G8_SNORM: 537 | case DXGI_FORMAT_R8G8_SINT: 538 | { 539 | TexelInfoR8G8_SNorm( texelInfo, srcPtr ); 540 | } 541 | break; 542 | 543 | case DXGI_FORMAT_R8G8_UNORM: 544 | case DXGI_FORMAT_R8G8_UINT: 545 | case DXGI_FORMAT_R8G8_TYPELESS: 546 | { 547 | TexelInfoR8G8_UNorm( texelInfo, srcPtr ); 548 | } 549 | break; 550 | 551 | case DXGI_FORMAT_X24_TYPELESS_G8_UINT: 552 | case DXGI_FORMAT_R24G8_TYPELESS: 553 | { 554 | TexelInfoR24G8_UInt( texelInfo, srcPtr ); 555 | } 556 | break; 557 | 558 | case DXGI_FORMAT_B8G8R8X8_UNORM: 559 | case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: 560 | { 561 | TexelInfoB8G8R8X8_UNorm( texelInfo, srcPtr ); 562 | } 563 | break; 564 | 565 | case DXGI_FORMAT_B8G8R8A8_UNORM: 566 | case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: 567 | { 568 | TexelInfoB8G8R8A8_UNorm( texelInfo, srcPtr ); 569 | } 570 | break; 571 | 572 | case DXGI_FORMAT_R10G10B10A2_TYPELESS: 573 | case DXGI_FORMAT_R10G10B10A2_UINT: 574 | case DXGI_FORMAT_R10G10B10A2_UNORM: 575 | { 576 | TexelInfoR10G10B10A2_UNorm( texelInfo, srcPtr ); 577 | } 578 | break; 579 | 580 | case DXGI_FORMAT_R8G8B8A8_TYPELESS: 581 | case DXGI_FORMAT_R8G8B8A8_UINT: 582 | case DXGI_FORMAT_R8G8B8A8_UNORM: 583 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: 584 | { 585 | TexelInfoR8G8B8A8_UNorm( texelInfo, srcPtr ); 586 | } 587 | break; 588 | 589 | case DXGI_FORMAT_R11G11B10_FLOAT: 590 | { 591 | TexelInfoR11G11B10_Float( texelInfo, srcPtr ); 592 | } 593 | break; 594 | 595 | case DXGI_FORMAT_R16G16_FLOAT: 596 | { 597 | TexelInfoR16G16_Float( texelInfo, srcPtr ); 598 | } 599 | break; 600 | 601 | case DXGI_FORMAT_R16G16B16A16_UINT: 602 | case DXGI_FORMAT_R16G16B16A16_UNORM: 603 | case DXGI_FORMAT_R16G16B16A16_TYPELESS: 604 | { 605 | TexelInfoR16G16B16A16_UNorm( texelInfo, srcPtr ); 606 | } 607 | break; 608 | 609 | case DXGI_FORMAT_R16G16B16A16_FLOAT: 610 | { 611 | TexelInfoR16G16B16A16_Float( texelInfo, srcPtr ); 612 | } 613 | break; 614 | 615 | case DXGI_FORMAT_R32G32B32_FLOAT: 616 | { 617 | TexelInfoR32G32B32_Float( texelInfo, srcPtr ); 618 | } 619 | break; 620 | 621 | case DXGI_FORMAT_R32G32B32A32_FLOAT: 622 | { 623 | TexelInfoR32G32B32A32_Float( texelInfo, srcPtr ); 624 | } 625 | break; 626 | 627 | case DXGI_FORMAT_R32G32B32A32_UINT: 628 | case DXGI_FORMAT_R32G32B32A32_TYPELESS: 629 | { 630 | TexelInfoR32G32B32A32_UInt( texelInfo, srcPtr ); 631 | } 632 | break; 633 | 634 | case DXGI_FORMAT_R32G32B32A32_SINT: 635 | { 636 | TexelInfoR32G32B32A32_SInt( texelInfo, srcPtr ); 637 | } 638 | break; 639 | 640 | case DXGI_FORMAT_R32_UINT: 641 | { 642 | TexelInfoR32_UInt( texelInfo, srcPtr ); 643 | } 644 | break; 645 | 646 | case DXGI_FORMAT_R32_SINT: 647 | { 648 | TexelInfoR32_SInt( texelInfo, srcPtr ); 649 | } 650 | break; 651 | 652 | case DXGI_FORMAT_D32_FLOAT: 653 | case DXGI_FORMAT_R32_FLOAT: 654 | case DXGI_FORMAT_R32_TYPELESS: 655 | { 656 | TexelInfoR32_Float( texelInfo, srcPtr ); 657 | } 658 | break; 659 | 660 | case DXGI_FORMAT_R16_FLOAT: 661 | { 662 | TexelInfoR16_Float( texelInfo, srcPtr ); 663 | } 664 | break; 665 | 666 | case DXGI_FORMAT_D16_UNORM: 667 | case DXGI_FORMAT_R16_UNORM: 668 | case DXGI_FORMAT_R16_UINT: 669 | case DXGI_FORMAT_R16_TYPELESS: 670 | case DXGI_FORMAT_R16_SNORM: 671 | case DXGI_FORMAT_R16_SINT: 672 | { 673 | TexelInfoD16_UNorm( texelInfo, srcPtr ); 674 | } 675 | break; 676 | 677 | case DXGI_FORMAT_R32G8X24_TYPELESS: 678 | case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: 679 | case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: 680 | { 681 | TexelInfoR32S8( texelInfo, srcPtr ); 682 | } 683 | break; 684 | } 685 | } 686 | 687 | 688 | QString texelDesc = QString::number( texelX ) + "x" + QString::number( texelY ); 689 | QString tooltip = texelDesc; 690 | 691 | QString const channelNames[ 4 ] = { "R:", "G:", "B:", "A:" }; 692 | for ( unsigned i = 0; i < 4; ++i ) 693 | { 694 | if ( !texelInfo[ i ].isEmpty() ) 695 | { 696 | texelDesc += " " + channelNames[ i ] + texelInfo[ i ]; 697 | tooltip += "\n" + channelNames[ i ] + texelInfo[ i ]; 698 | } 699 | } 700 | 701 | extern CMainWindow* GMainWindow; 702 | GMainWindow->SetStatusRight( texelDesc ); 703 | QToolTip::showText( QCursor::pos(), tooltip ); 704 | } 705 | 706 | void CImageWindow::wheelEvent( QWheelEvent* event ) 707 | { 708 | float newZoom = m_zoom; 709 | if ( event->angleDelta().y() < 0 ) 710 | { 711 | newZoom *= 0.5f; 712 | } 713 | else 714 | { 715 | newZoom *= 2.0f; 716 | } 717 | newZoom = ClampZoom( newZoom ); 718 | 719 | if ( fabs( newZoom - m_zoom ) > 0.001f ) 720 | { 721 | float prevTexelX = ( event->x() + horizontalScrollBar()->value() - 0.5f ) / m_zoom; 722 | float prevTexelY = ( event->y() + verticalScrollBar()->value() - 0.5f ) / m_zoom; 723 | 724 | m_zoom = newZoom; 725 | m_imageLabel.SetZoom( newZoom ); 726 | m_imageLabel.setFixedSize( m_imageWidth * newZoom, m_imageHeight * newZoom ); 727 | 728 | // scroll in order to hold to the same texel under the cursor after the zoom 729 | horizontalScrollBar()->setValue( prevTexelX * m_zoom - event->x() + 0.5f ); 730 | verticalScrollBar()->setValue( prevTexelY * m_zoom - event->y() + 0.5f ); 731 | 732 | UpdateTitle(); 733 | } 734 | 735 | event->accept(); 736 | } 737 | 738 | CImageLabel::CImageLabel() 739 | : m_zoom( 1.0f ) 740 | { 741 | 742 | } 743 | 744 | void CImageLabel::SetZoom( float zoom ) 745 | { 746 | m_zoom = zoom; 747 | } 748 | 749 | void CImageLabel::SetImage( QImage const& image ) 750 | { 751 | m_pixmap = QPixmap::fromImage( image ); 752 | } 753 | 754 | void CImageLabel::paintEvent( QPaintEvent* event ) 755 | { 756 | QPainter paint( this ); 757 | 758 | QRect dstRect( 0, 0, m_pixmap.width() * m_zoom, m_pixmap.height() * m_zoom ); 759 | QRect srcRect( 0, 0, m_pixmap.width(), m_pixmap.height() ); 760 | 761 | paint.drawPixmap( dstRect, m_pixmap, srcRect ); 762 | } -------------------------------------------------------------------------------- /imageWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "baseWindow.h" 4 | 5 | class CImageLabel : public QLabel 6 | { 7 | Q_OBJECT 8 | 9 | public: 10 | CImageLabel(); 11 | void SetZoom( float zoom ); 12 | void SetImage( QImage const& image ); 13 | 14 | 15 | private: 16 | QPixmap m_pixmap; 17 | float m_zoom; 18 | 19 | void paintEvent( QPaintEvent* event ) Q_DECL_OVERRIDE; 20 | }; 21 | 22 | class CImageWindow : public QScrollArea, public CBaseWindow 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | CImageWindow(); 28 | bool LoadFile( QString const& path ); 29 | virtual void Reload(); 30 | virtual void ZoomIn(); 31 | virtual void ZoomOut(); 32 | virtual void SetViewChannel( EViewChannel channel ); 33 | virtual void SetViewFace( unsigned face ); 34 | virtual void SetViewMipMap( unsigned mipMap ); 35 | virtual void SetViewMin( float min ); 36 | virtual void SetViewMax( float max ); 37 | virtual void SetViewGamma( float gamma ); 38 | virtual void SetViewDiffMult( float mult ) {} 39 | virtual QSize GetInitialSize() const { return QSize( m_imageWidth, m_imageHeight ); } 40 | virtual QString const& GetTitle() const { return m_title; } 41 | virtual EViewChannel GetViewChannel() const { return m_viewChannel; } 42 | virtual unsigned GetMipNum() const { return m_info.mipLevels; } 43 | virtual unsigned GetFaceNum() const { return m_info.arraySize; } 44 | virtual unsigned GetViewFace() const { return m_viewFace; } 45 | virtual unsigned GetViewMipMap() const { return m_viewMipMap; } 46 | virtual float GetViewMin() const { return m_viewMin; } 47 | virtual float GetViewMax() const { return m_viewMax; } 48 | virtual float GetViewGamma() const { return m_viewGamma; } 49 | virtual float GetViewDiffMult() const { return 1.0f; } 50 | 51 | 52 | private: 53 | QString m_title; 54 | DirectX::ScratchImage m_scratchImage; 55 | DirectX::TexMetadata m_info; 56 | QString m_path; 57 | QString m_fileName; 58 | QString m_formatName; 59 | CImageLabel m_imageLabel; 60 | float m_zoom; 61 | bool m_dragEnabled; 62 | QPoint m_dragStart; 63 | EViewChannel m_viewChannel; 64 | unsigned m_texelSizeInBytes; 65 | unsigned m_viewFace; 66 | unsigned m_viewMipMap; 67 | float m_viewMin; 68 | float m_viewMax; 69 | float m_viewGamma; 70 | unsigned m_imageWidth; 71 | unsigned m_imageHeight; 72 | 73 | QPoint m_selectionStart; 74 | QPoint m_selectionEnd; 75 | QRubberBand m_selection; 76 | 77 | void mousePressEvent( QMouseEvent* event ) Q_DECL_OVERRIDE; 78 | void mouseReleaseEvent( QMouseEvent* event ) Q_DECL_OVERRIDE; 79 | void mouseMoveEvent( QMouseEvent* event ) Q_DECL_OVERRIDE; 80 | void wheelEvent( QWheelEvent* event ) Q_DECL_OVERRIDE; 81 | void PickTexel( QPoint const& pos ); 82 | void UpdateImage(); 83 | void UpdateTitle(); 84 | }; -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "mainWindow.h" 3 | 4 | CMainWindow* GMainWindow = nullptr; 5 | 6 | int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, char* lpCmdLine, int nShowCmd ) 7 | { 8 | QCoreApplication::setApplicationName( "ProgImgView" ); 9 | QCoreApplication::setOrganizationName( "Kris" ); 10 | QCoreApplication::setApplicationVersion( "1.11" ); 11 | 12 | QApplication app( __argc, __argv ); 13 | 14 | GMainWindow = new CMainWindow; 15 | GMainWindow->show(); 16 | 17 | for ( unsigned i = 1; i < app.arguments().count(); ++i ) 18 | { 19 | GMainWindow->OpenFile( app.arguments().at( i ) ); 20 | } 21 | 22 | return app.exec(); 23 | } -------------------------------------------------------------------------------- /mainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "mainWindow.h" 3 | #include "imageWindow.h" 4 | #include "compareWindow.h" 5 | 6 | CMainWindow::CMainWindow() 7 | { 8 | m_mdiArea.setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); 9 | m_mdiArea.setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded ); 10 | setCentralWidget( &m_mdiArea ); 11 | 12 | CreateToolbar(); 13 | ReadSettings(); 14 | 15 | setWindowTitle( QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion() ); 16 | setAcceptDrops( true ); 17 | SetStatusRight( "Hold right mouse button to pick texel. Mouse wheel to zoom. Shift+mouse to zoom to rect." ); 18 | connect( &m_mdiArea, &QMdiArea::subWindowActivated, this, &CMainWindow::SubWindowActivated ); 19 | } 20 | 21 | void CMainWindow::closeEvent( QCloseEvent* event ) 22 | { 23 | m_mdiArea.closeAllSubWindows(); 24 | if ( m_mdiArea.currentSubWindow() ) 25 | { 26 | event->ignore(); 27 | } 28 | else 29 | { 30 | WriteSettings(); 31 | event->accept(); 32 | } 33 | } 34 | 35 | void CMainWindow::dragEnterEvent( QDragEnterEvent* event ) 36 | { 37 | if ( event->mimeData()->hasUrls() ) 38 | { 39 | event->acceptProposedAction(); 40 | } 41 | } 42 | 43 | void CMainWindow::dropEvent( QDropEvent* event ) 44 | { 45 | QList droppedUrls = event->mimeData()->urls(); 46 | for( unsigned i = 0; i < droppedUrls.size(); i++) 47 | { 48 | OpenFile( droppedUrls[ i ].toLocalFile() ); 49 | } 50 | 51 | event->acceptProposedAction(); 52 | } 53 | 54 | char const* GOpenFileFilter = "Images (*.dds;*.tga;*.jpg;*.bmp;*.png;*.hdr;*.exr);;All files (*.*)"; 55 | 56 | void CMainWindow::Open() 57 | { 58 | QString const fileName = QFileDialog::getOpenFileName( this, "Open image", m_lastDirectory, GOpenFileFilter ); 59 | if ( !fileName.isEmpty() ) 60 | { 61 | m_lastDirectory = fileName; 62 | OpenFile( fileName ); 63 | } 64 | } 65 | 66 | void CMainWindow::Compare() 67 | { 68 | QString const fileName0 = QFileDialog::getOpenFileName( this, "Open first image", m_lastDirectory, GOpenFileFilter ); 69 | if ( !fileName0.isEmpty() ) 70 | { 71 | m_lastDirectory = fileName0; 72 | QString const fileName1 = QFileDialog::getOpenFileName( this, "Open first image", m_lastDirectory, GOpenFileFilter ); 73 | if ( !fileName1.isEmpty() ) 74 | { 75 | m_lastDirectory = fileName1; 76 | 77 | CompareFiles( fileName0, fileName1 ); 78 | } 79 | } 80 | } 81 | 82 | void CMainWindow::ReloadCurrent() 83 | { 84 | CBaseWindow* baseWindow = ActiveWindow(); 85 | if ( baseWindow ) 86 | { 87 | baseWindow->Reload(); 88 | } 89 | } 90 | 91 | bool CMainWindow::OpenFile( QString fileName ) 92 | { 93 | CImageWindow* imageWindow = new CImageWindow(); 94 | m_mdiArea.addSubWindow( imageWindow ); 95 | 96 | bool const ret = imageWindow->LoadFile( fileName ); 97 | if ( ret ) 98 | { 99 | UpdateToolbar( imageWindow ); 100 | imageWindow->show(); 101 | 102 | QSize reqSize = imageWindow->GetInitialSize() + QSize( 4, 4 ) + imageWindow->parentWidget()->size() - imageWindow->size(); 103 | reqSize = reqSize.boundedTo( m_mdiArea.size() ); 104 | reqSize = reqSize.expandedTo( QSize( 128, 128 ) ); 105 | imageWindow->parentWidget()->resize( reqSize ); 106 | } 107 | else 108 | { 109 | imageWindow->close(); 110 | } 111 | 112 | AddToRecentFiles( fileName ); 113 | return ret; 114 | } 115 | 116 | bool CMainWindow::CompareFiles( QString const& fileName0, QString const& fileName1 ) 117 | { 118 | CCompareWindow* compareWindow = new CCompareWindow(); 119 | m_mdiArea.addSubWindow( compareWindow ); 120 | 121 | bool const ret = compareWindow->LoadFiles( fileName0, fileName1 ); 122 | if ( ret ) 123 | { 124 | UpdateToolbar( compareWindow ); 125 | 126 | compareWindow->show(); 127 | 128 | QSize reqSize = compareWindow->GetInitialSize() + QSize( 4, 4 ) + compareWindow->parentWidget()->size() - compareWindow->size(); 129 | reqSize = reqSize.boundedTo( m_mdiArea.size() ); 130 | reqSize = reqSize.expandedTo( QSize( 128, 128 ) ); 131 | compareWindow->parentWidget()->resize( reqSize ); 132 | } 133 | else 134 | { 135 | compareWindow->close(); 136 | } 137 | 138 | return ret; 139 | } 140 | 141 | void CMainWindow::OpenRecentFile() 142 | { 143 | if ( QAction const* action = qobject_cast( sender() ) ) 144 | { 145 | OpenFile( action->text() ); 146 | } 147 | } 148 | 149 | void CMainWindow::ZoomIn() 150 | { 151 | CBaseWindow* baseWindow = ActiveWindow(); 152 | if ( baseWindow ) 153 | { 154 | baseWindow->ZoomIn(); 155 | } 156 | } 157 | 158 | void CMainWindow::ZoomOut() 159 | { 160 | CBaseWindow* baseWindow = ActiveWindow(); 161 | if ( baseWindow ) 162 | { 163 | baseWindow->ZoomOut(); 164 | } 165 | } 166 | 167 | void CMainWindow::ViewAction() 168 | { 169 | QObject const* sender = QObject::sender(); 170 | for ( unsigned i = 0; i < ARRAYSIZE( m_actionView ); ++i ) 171 | { 172 | if ( sender == m_actionView[ i ] ) 173 | { 174 | m_channelComboBox.setCurrentIndex( i ); 175 | break; 176 | } 177 | } 178 | } 179 | 180 | void CMainWindow::ChangeChannel( int channel ) 181 | { 182 | CBaseWindow* baseWindow = ActiveWindow(); 183 | if ( baseWindow ) 184 | { 185 | baseWindow->SetViewChannel( (EViewChannel) channel ); 186 | } 187 | } 188 | 189 | void CMainWindow::ChangeFace( int face ) 190 | { 191 | CBaseWindow* baseWindow = ActiveWindow(); 192 | if ( baseWindow ) 193 | { 194 | baseWindow->SetViewFace( face ); 195 | } 196 | } 197 | 198 | void CMainWindow::ChangeMip( int mip ) 199 | { 200 | CBaseWindow* baseWindow = ActiveWindow(); 201 | if ( baseWindow ) 202 | { 203 | baseWindow->SetViewMipMap( mip ); 204 | } 205 | } 206 | 207 | void CMainWindow::ChangeVisMin( float visMin ) 208 | { 209 | CBaseWindow* baseWindow = ActiveWindow(); 210 | if ( baseWindow ) 211 | { 212 | baseWindow->SetViewMin( visMin ); 213 | } 214 | } 215 | 216 | void CMainWindow::ChangeVisMax( float visMax ) 217 | { 218 | CBaseWindow* baseWindow = ActiveWindow(); 219 | if ( baseWindow ) 220 | { 221 | baseWindow->SetViewMax( visMax ); 222 | } 223 | } 224 | 225 | void CMainWindow::ChangeVisGamma( float visGamma ) 226 | { 227 | CBaseWindow* baseWindow = ActiveWindow(); 228 | if ( baseWindow ) 229 | { 230 | baseWindow->SetViewGamma( visGamma ); 231 | } 232 | } 233 | 234 | void CMainWindow::ChangeVisDiffMult( float mult ) 235 | { 236 | CBaseWindow* baseWindow = ActiveWindow(); 237 | if ( baseWindow ) 238 | { 239 | baseWindow->SetViewDiffMult( mult ); 240 | } 241 | } 242 | 243 | void CMainWindow::SubWindowActivated( QMdiSubWindow* window ) 244 | { 245 | UpdateToolbar( ActiveWindow() ); 246 | } 247 | 248 | void CMainWindow::CreateToolbar() 249 | { 250 | statusBar()->addPermanentWidget( &m_statusLeft, 1 ); 251 | statusBar()->addPermanentWidget( &m_statusRight, 1 ); 252 | 253 | QToolBar* toolBar = addToolBar( tr( "Main" ) ); 254 | 255 | m_channelComboBox.addItem( "View RGB" ); 256 | m_channelComboBox.addItem( "View R" ); 257 | m_channelComboBox.addItem( "View G" ); 258 | m_channelComboBox.addItem( "View B" ); 259 | m_channelComboBox.addItem( "View A" ); 260 | toolBar->addWidget( &m_channelComboBox ); 261 | connect( &m_channelComboBox, static_cast< void (QComboBox::*)( int ) >( &QComboBox::currentIndexChanged ), this, &CMainWindow::ChangeChannel ); 262 | 263 | toolBar->addWidget( &m_faceComboBox ); 264 | connect( &m_faceComboBox, static_cast< void (QComboBox::*)( int ) >( &QComboBox::currentIndexChanged ), this, &CMainWindow::ChangeFace ); 265 | 266 | toolBar->addWidget( &m_mipComboBox ); 267 | connect( &m_mipComboBox, static_cast< void (QComboBox::*)( int ) >( &QComboBox::currentIndexChanged ), this, &CMainWindow::ChangeMip ); 268 | 269 | m_visMinSpinBox.setSingleStep( 0.1 ); 270 | m_visMinSpinBox.setPrefix( "min: " ); 271 | m_visMinSpinBox.setRange( -FLT_MAX, FLT_MAX ); 272 | toolBar->addWidget( &m_visMinSpinBox ); 273 | connect( &m_visMinSpinBox, static_cast< void (QDoubleSpinBox::*)( double ) >( &QDoubleSpinBox::valueChanged ), this, &CMainWindow::ChangeVisMin ); 274 | 275 | m_visMaxSpinBox.setSingleStep( 0.1 ); 276 | m_visMaxSpinBox.setPrefix( "max: " ); 277 | m_visMaxSpinBox.setRange( -FLT_MAX, FLT_MAX ); 278 | toolBar->addWidget( &m_visMaxSpinBox ); 279 | connect( &m_visMaxSpinBox, static_cast< void (QDoubleSpinBox::*)( double ) >( &QDoubleSpinBox::valueChanged ), this, &CMainWindow::ChangeVisMax ); 280 | 281 | m_visGammaSpinBox.setSingleStep( 0.1 ); 282 | m_visGammaSpinBox.setRange( 0.01, 100.0 ); 283 | m_visGammaSpinBox.setPrefix( "gamma: " ); 284 | toolBar->addWidget( &m_visGammaSpinBox ); 285 | connect( &m_visGammaSpinBox, static_cast< void (QDoubleSpinBox::*)( double ) >( &QDoubleSpinBox::valueChanged ), this, &CMainWindow::ChangeVisGamma ); 286 | 287 | m_visDiffMultSpinBox.setSingleStep( 1.0 ); 288 | m_visDiffMultSpinBox.setRange( 0.01, FLT_MAX ); 289 | m_visDiffMultSpinBox.setPrefix( "diff mult: " ); 290 | toolBar->addWidget( &m_visDiffMultSpinBox ); 291 | connect( &m_visDiffMultSpinBox, static_cast< void (QDoubleSpinBox::*)( double ) >( &QDoubleSpinBox::valueChanged ), this, &CMainWindow::ChangeVisDiffMult ); 292 | 293 | QMenu* fileMenu = menuBar()->addMenu( "File" ); 294 | 295 | m_actionOpen = new QAction( "Open...", this ); 296 | m_actionOpen->setShortcuts( QKeySequence::Open ); 297 | connect( m_actionOpen, &QAction::triggered, this, &CMainWindow::Open ); 298 | fileMenu->addAction( m_actionOpen ); 299 | 300 | m_actionCompare = new QAction( "Compare...", this ); 301 | connect( m_actionCompare, &QAction::triggered, this, &CMainWindow::Compare ); 302 | fileMenu->addAction( m_actionCompare ); 303 | 304 | m_actionReloadCurrent = new QAction( "Reload current", this ); 305 | m_actionReloadCurrent->setShortcut( QKeySequence( "R" ) ); 306 | connect( m_actionReloadCurrent, &QAction::triggered, this, &CMainWindow::ReloadCurrent ); 307 | fileMenu->addAction( m_actionReloadCurrent ); 308 | 309 | fileMenu->addSeparator(); 310 | 311 | QMenu* recentMenu = fileMenu->addMenu( "Recent..." ); 312 | m_actionRecentFileSubMenuAct = recentMenu->menuAction(); 313 | 314 | for ( int i = 0; i < ARRAYSIZE( m_actionRecentFile ); ++i ) 315 | { 316 | m_actionRecentFile[ i ] = recentMenu->addAction( QString(), this, &CMainWindow::OpenRecentFile ); 317 | m_actionRecentFile[ i ]->setVisible( false ); 318 | } 319 | 320 | m_actionRecentFileSeparator = fileMenu->addSeparator(); 321 | fileMenu->addSeparator(); 322 | 323 | QAction *exitAct = fileMenu->addAction( "Exit", qApp, &QApplication::closeAllWindows); 324 | exitAct->setShortcuts( QKeySequence::Quit ); 325 | fileMenu->addAction( exitAct ); 326 | 327 | 328 | m_windowMenu = menuBar()->addMenu( "View" ); 329 | 330 | m_actionZoomIn = new QAction( "Zoom In", this ); 331 | m_actionZoomIn->setShortcut( QKeySequence( "+" ) ); 332 | connect( m_actionZoomIn, &QAction::triggered, this, &CMainWindow::ZoomIn ); 333 | m_windowMenu->addAction( m_actionZoomIn ); 334 | 335 | m_actionZoomOut = new QAction( "Zoom Out", this ); 336 | m_actionZoomOut->setShortcut( QKeySequence( "-" ) ); 337 | connect( m_actionZoomOut, &QAction::triggered, this, &CMainWindow::ZoomOut ); 338 | m_windowMenu->addAction( m_actionZoomOut ); 339 | 340 | 341 | m_actionView[ 0 ] = new QAction( "View RGB", this ); 342 | m_actionView[ 0 ]->setShortcut( QKeySequence( "1" ) ); 343 | m_actionView[ 1 ] = new QAction( "View R", this ); 344 | m_actionView[ 1 ]->setShortcut( QKeySequence( "2" ) ); 345 | m_actionView[ 2 ] = new QAction( "View G", this ); 346 | m_actionView[ 2 ]->setShortcut( QKeySequence( "3" ) ); 347 | m_actionView[ 3 ] = new QAction( "View B", this ); 348 | m_actionView[ 3 ]->setShortcut( QKeySequence( "4" ) ); 349 | m_actionView[ 4 ] = new QAction( "View A", this ); 350 | m_actionView[ 4 ]->setShortcut( QKeySequence( "5" ) ); 351 | for ( unsigned i = 0; i < ARRAYSIZE( m_actionView ); ++i ) 352 | { 353 | connect( m_actionView[ i ], &QAction::triggered, this, &CMainWindow::ViewAction ); 354 | m_windowMenu->addAction( m_actionView[ i ] ); 355 | } 356 | 357 | 358 | m_windowMenu = menuBar()->addMenu( "Window" ); 359 | 360 | m_actionClose = new QAction( "Close", this); 361 | connect( m_actionClose, &QAction::triggered, &m_mdiArea, &QMdiArea::closeActiveSubWindow ); 362 | 363 | m_actionCloseAll = new QAction( "Close All", this ); 364 | connect( m_actionCloseAll, &QAction::triggered, &m_mdiArea, &QMdiArea::closeAllSubWindows ); 365 | 366 | m_actionTile = new QAction( "Tile", this); 367 | connect( m_actionTile, &QAction::triggered, &m_mdiArea, &QMdiArea::tileSubWindows ); 368 | 369 | m_actionCascade = new QAction( "Cascade", this); 370 | connect( m_actionCascade, &QAction::triggered, &m_mdiArea, &QMdiArea::cascadeSubWindows ); 371 | 372 | m_actionNext = new QAction( "Next", this); 373 | m_actionNext->setShortcuts( QKeySequence::NextChild ); 374 | connect( m_actionNext, &QAction::triggered, &m_mdiArea, &QMdiArea::activateNextSubWindow ); 375 | 376 | m_actionPrevious = new QAction( "Previous", this ); 377 | m_actionPrevious->setShortcuts( QKeySequence::PreviousChild ); 378 | connect( m_actionPrevious, &QAction::triggered, &m_mdiArea, &QMdiArea::activatePreviousSubWindow ); 379 | 380 | m_actionWindowMenuSeparator = new QAction( this ); 381 | m_actionWindowMenuSeparator->setSeparator( true ); 382 | 383 | m_windowMenu->addAction( m_actionClose ); 384 | m_windowMenu->addAction( m_actionCloseAll ); 385 | m_windowMenu->addSeparator(); 386 | m_windowMenu->addAction( m_actionTile ); 387 | m_windowMenu->addAction( m_actionCascade ); 388 | m_windowMenu->addSeparator(); 389 | m_windowMenu->addAction( m_actionNext ); 390 | m_windowMenu->addAction( m_actionPrevious ); 391 | m_windowMenu->addAction( m_actionWindowMenuSeparator ); 392 | 393 | UpdateToolbar( nullptr ); 394 | } 395 | 396 | void CMainWindow::ReadSettings() 397 | { 398 | QSettings settings( QCoreApplication::organizationName(), QCoreApplication::applicationName() ); 399 | QByteArray geometry = settings.value( "geometry", QByteArray() ).toByteArray(); 400 | m_lastDirectory = settings.value( "last_directory" ).toString(); 401 | 402 | if ( geometry.isEmpty() ) 403 | { 404 | QRect availableGeometry = QApplication::desktop()->availableGeometry( this ); 405 | resize( availableGeometry.width() / 3, availableGeometry.height() / 2 ); 406 | move( ( availableGeometry.width() - width() ) / 2, ( availableGeometry.height() - height() ) / 2 ); 407 | } 408 | else 409 | { 410 | restoreGeometry( geometry ); 411 | } 412 | 413 | unsigned const recentFileNum = settings.beginReadArray( "recent_files" ); 414 | for ( unsigned i = 0; i < recentFileNum && i < ARRAYSIZE( m_actionRecentFile ); ++i ) 415 | { 416 | settings.setArrayIndex( i ); 417 | QString recentFile = settings.value( "file" ).toString(); 418 | m_actionRecentFile[ i ]->setText( recentFile ); 419 | m_actionRecentFile[ i ]->setVisible( true ); 420 | } 421 | } 422 | 423 | void CMainWindow::AddToRecentFiles( QString const& fileName ) 424 | { 425 | if ( m_actionRecentFile[ 0 ]->text() != fileName ) 426 | { 427 | for ( unsigned i = ARRAYSIZE( m_actionRecentFile ) - 1; i > 0; --i ) 428 | { 429 | m_actionRecentFile[ i ]->setText( m_actionRecentFile[ i - 1 ]->text() ); 430 | m_actionRecentFile[ i ]->setVisible( m_actionRecentFile[ i - 1 ]->isVisible() ); 431 | } 432 | m_actionRecentFile[ 0 ]->setText( fileName ); 433 | m_actionRecentFile[ 0 ]->setVisible( true ); 434 | } 435 | } 436 | 437 | void CMainWindow::WriteSettings() 438 | { 439 | QSettings settings( QCoreApplication::organizationName(), QCoreApplication::applicationName() ); 440 | settings.setValue( "geometry", saveGeometry() ); 441 | settings.setValue( "last_directory", m_lastDirectory ); 442 | 443 | settings.beginWriteArray( "recent_files" ); 444 | for ( unsigned i = 0; i < ARRAYSIZE( m_actionRecentFile ); ++i ) 445 | { 446 | if ( m_actionRecentFile[ i ]->isVisible() ) 447 | { 448 | settings.setArrayIndex( i ); 449 | settings.setValue( "file", m_actionRecentFile[ i ]->text() ); 450 | } 451 | } 452 | settings.endArray(); 453 | } 454 | 455 | CBaseWindow* CMainWindow::ActiveWindow() const 456 | { 457 | if ( QMdiSubWindow* activeSubWindow = m_mdiArea.activeSubWindow() ) 458 | { 459 | return dynamic_cast( activeSubWindow->widget() ); 460 | } 461 | return nullptr; 462 | } 463 | 464 | void CMainWindow::UpdateToolbar( CBaseWindow* baseWindow ) 465 | { 466 | m_channelComboBox.blockSignals( true ); 467 | m_faceComboBox.blockSignals( true ); 468 | m_mipComboBox.blockSignals( true ); 469 | m_visMinSpinBox.blockSignals( true ); 470 | m_visMaxSpinBox.blockSignals( true ); 471 | m_visGammaSpinBox.blockSignals( true ); 472 | m_visDiffMultSpinBox.blockSignals( true ); 473 | 474 | 475 | m_channelComboBox.setCurrentIndex( 0 ); 476 | 477 | m_faceComboBox.clear(); 478 | m_faceComboBox.addItem( "Face: 0" ); 479 | m_faceComboBox.setCurrentIndex( 0 ); 480 | 481 | m_mipComboBox.clear(); 482 | m_mipComboBox.addItem( "Mip: 0" ); 483 | m_mipComboBox.setCurrentIndex( 0 ); 484 | 485 | m_visMinSpinBox.setValue( 0.0 ); 486 | m_visMaxSpinBox.setValue( 1.0 ); 487 | m_visGammaSpinBox.setValue( 1.0 ); 488 | m_visDiffMultSpinBox.setValue( 1.0 ); 489 | 490 | if ( baseWindow ) 491 | { 492 | for ( unsigned i = 1; i < baseWindow->GetFaceNum(); ++i ) 493 | { 494 | m_faceComboBox.addItem( "Face: " + QString::number( i ) ); 495 | } 496 | m_faceComboBox.setCurrentIndex( baseWindow->GetViewFace() ); 497 | 498 | for ( unsigned i = 1; i < baseWindow->GetMipNum(); ++i ) 499 | { 500 | m_mipComboBox.addItem( "Mip: " + QString::number( i ) ); 501 | } 502 | m_mipComboBox.setCurrentIndex( baseWindow->GetViewMipMap() ); 503 | 504 | m_channelComboBox.setCurrentIndex( (int) baseWindow->GetViewChannel() ); 505 | m_visMinSpinBox.setValue( baseWindow->GetViewMin() ); 506 | m_visMaxSpinBox.setValue( baseWindow->GetViewMax() ); 507 | m_visGammaSpinBox.setValue( baseWindow->GetViewGamma() ); 508 | m_visDiffMultSpinBox.setValue( baseWindow->GetViewDiffMult() ); 509 | } 510 | 511 | SetStatusLeft( baseWindow ? baseWindow->GetTitle() : "" ); 512 | 513 | m_channelComboBox.blockSignals( false ); 514 | m_faceComboBox.blockSignals( false ); 515 | m_mipComboBox.blockSignals( false ); 516 | m_visMinSpinBox.blockSignals( false ); 517 | m_visMaxSpinBox.blockSignals( false ); 518 | m_visGammaSpinBox.blockSignals( false ); 519 | m_visDiffMultSpinBox.blockSignals( false ); 520 | } 521 | 522 | void CMainWindow::SetStatusLeft( QString const& status ) 523 | { 524 | m_statusLeft.setText( status ); 525 | } 526 | 527 | void CMainWindow::SetStatusRight( QString const& status ) 528 | { 529 | m_statusRight.setText( status ); 530 | } -------------------------------------------------------------------------------- /mainWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CImageWindow; 4 | class CBaseWindow; 5 | class QAction; 6 | class QMenu; 7 | class QMdiArea; 8 | class QMdiSubWindow; 9 | 10 | class CMainWindow : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | CMainWindow(); 16 | void SetStatusLeft( QString const& status ); 17 | void SetStatusRight( QString const& status ); 18 | bool OpenFile( QString fileName ); 19 | 20 | 21 | private slots: 22 | void Open(); 23 | void Compare(); 24 | void ReloadCurrent(); 25 | void OpenRecentFile(); 26 | void ZoomIn(); 27 | void ZoomOut(); 28 | void ViewAction(); 29 | void ChangeChannel( int channel ); 30 | void ChangeFace( int face ); 31 | void ChangeMip( int mip ); 32 | void ChangeVisMin( float visMin ); 33 | void ChangeVisMax( float visMax ); 34 | void ChangeVisGamma( float visGamma ); 35 | void ChangeVisDiffMult( float mult ); 36 | void SubWindowActivated( QMdiSubWindow* window ); 37 | 38 | 39 | private: 40 | void UpdateToolbar( CBaseWindow* baseWindow ); 41 | void UpdateTitle( CBaseWindow* baseWindow ); 42 | void closeEvent( QCloseEvent* event ) Q_DECL_OVERRIDE; 43 | void dragEnterEvent( QDragEnterEvent* event ) Q_DECL_OVERRIDE; 44 | void dropEvent( QDropEvent* event ) Q_DECL_OVERRIDE; 45 | void CreateToolbar(); 46 | void ReadSettings(); 47 | void WriteSettings(); 48 | void AddToRecentFiles( QString const& fileName ); 49 | bool CompareFiles( QString const& fileName0, QString const& fileName1 ); 50 | CBaseWindow* ActiveWindow() const; 51 | 52 | QString m_lastDirectory; 53 | QMdiArea m_mdiArea; 54 | QMenu* m_windowMenu; 55 | QComboBox m_channelComboBox; 56 | QComboBox m_faceComboBox; 57 | QComboBox m_mipComboBox; 58 | QDoubleSpinBox m_visMinSpinBox; 59 | QDoubleSpinBox m_visMaxSpinBox; 60 | QDoubleSpinBox m_visGammaSpinBox; 61 | QDoubleSpinBox m_visDiffMultSpinBox; 62 | QLabel m_statusLeft; 63 | QLabel m_statusRight; 64 | QAction* m_actionRecentFile[ 10 ]; 65 | QAction* m_actionRecentFileSeparator; 66 | QAction* m_actionRecentFileSubMenuAct; 67 | QAction* m_actionOpen; 68 | QAction* m_actionCompare; 69 | QAction* m_actionReloadCurrent; 70 | QAction* m_actionClose; 71 | QAction* m_actionCloseAll; 72 | QAction* m_actionTile; 73 | QAction* m_actionCascade; 74 | QAction* m_actionNext; 75 | QAction* m_actionPrevious; 76 | QAction* m_actionWindowMenuSeparator; 77 | QAction* m_actionZoomIn; 78 | QAction* m_actionZoomOut; 79 | QAction* m_actionView[ 5 ]; 80 | }; -------------------------------------------------------------------------------- /moc.bat: -------------------------------------------------------------------------------- 1 | a:\qt\qt_5_7_0\qt5-x64-shared-release\bin\moc.exe imageWindow.h -o moc_imageWindow.cpp -b stdafx.h 2 | a:\qt\qt_5_7_0\qt5-x64-shared-release\bin\moc.exe compareWindow.h -o moc_compareWindow.cpp -b stdafx.h 3 | a:\qt\qt_5_7_0\qt5-x64-shared-release\bin\moc.exe mainWindow.h -o moc_mainWindow.cpp -b stdafx.h -------------------------------------------------------------------------------- /moc_compareWindow.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Meta object code from reading C++ file 'compareWindow.h' 3 | ** 4 | ** Created by: The Qt Meta Object Compiler version 67 (Qt 5.7.0) 5 | ** 6 | ** WARNING! All changes made in this file will be lost! 7 | *****************************************************************************/ 8 | 9 | #include "stdafx.h" 10 | #include "compareWindow.h" 11 | #include 12 | #include 13 | #if !defined(Q_MOC_OUTPUT_REVISION) 14 | #error "The header file 'compareWindow.h' doesn't include ." 15 | #elif Q_MOC_OUTPUT_REVISION != 67 16 | #error "This file was generated using the moc from 5.7.0. It" 17 | #error "cannot be used with the include files from this version of Qt." 18 | #error "(The moc has changed too much.)" 19 | #endif 20 | 21 | QT_BEGIN_MOC_NAMESPACE 22 | struct qt_meta_stringdata_CCompareImageLabel_t { 23 | QByteArrayData data[1]; 24 | char stringdata0[19]; 25 | }; 26 | #define QT_MOC_LITERAL(idx, ofs, len) \ 27 | Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ 28 | qptrdiff(offsetof(qt_meta_stringdata_CCompareImageLabel_t, stringdata0) + ofs \ 29 | - idx * sizeof(QByteArrayData)) \ 30 | ) 31 | static const qt_meta_stringdata_CCompareImageLabel_t qt_meta_stringdata_CCompareImageLabel = { 32 | { 33 | QT_MOC_LITERAL(0, 0, 18) // "CCompareImageLabel" 34 | 35 | }, 36 | "CCompareImageLabel" 37 | }; 38 | #undef QT_MOC_LITERAL 39 | 40 | static const uint qt_meta_data_CCompareImageLabel[] = { 41 | 42 | // content: 43 | 7, // revision 44 | 0, // classname 45 | 0, 0, // classinfo 46 | 0, 0, // methods 47 | 0, 0, // properties 48 | 0, 0, // enums/sets 49 | 0, 0, // constructors 50 | 0, // flags 51 | 0, // signalCount 52 | 53 | 0 // eod 54 | }; 55 | 56 | void CCompareImageLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 57 | { 58 | Q_UNUSED(_o); 59 | Q_UNUSED(_id); 60 | Q_UNUSED(_c); 61 | Q_UNUSED(_a); 62 | } 63 | 64 | const QMetaObject CCompareImageLabel::staticMetaObject = { 65 | { &QLabel::staticMetaObject, qt_meta_stringdata_CCompareImageLabel.data, 66 | qt_meta_data_CCompareImageLabel, qt_static_metacall, Q_NULLPTR, Q_NULLPTR} 67 | }; 68 | 69 | 70 | const QMetaObject *CCompareImageLabel::metaObject() const 71 | { 72 | return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; 73 | } 74 | 75 | void *CCompareImageLabel::qt_metacast(const char *_clname) 76 | { 77 | if (!_clname) return Q_NULLPTR; 78 | if (!strcmp(_clname, qt_meta_stringdata_CCompareImageLabel.stringdata0)) 79 | return static_cast(const_cast< CCompareImageLabel*>(this)); 80 | return QLabel::qt_metacast(_clname); 81 | } 82 | 83 | int CCompareImageLabel::qt_metacall(QMetaObject::Call _c, int _id, void **_a) 84 | { 85 | _id = QLabel::qt_metacall(_c, _id, _a); 86 | if (_id < 0) 87 | return _id; 88 | return _id; 89 | } 90 | struct qt_meta_stringdata_CCompareWindow_t { 91 | QByteArrayData data[9]; 92 | char stringdata0[122]; 93 | }; 94 | #define QT_MOC_LITERAL(idx, ofs, len) \ 95 | Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ 96 | qptrdiff(offsetof(qt_meta_stringdata_CCompareWindow_t, stringdata0) + ofs \ 97 | - idx * sizeof(QByteArrayData)) \ 98 | ) 99 | static const qt_meta_stringdata_CCompareWindow_t qt_meta_stringdata_CCompareWindow = { 100 | { 101 | QT_MOC_LITERAL(0, 0, 14), // "CCompareWindow" 102 | QT_MOC_LITERAL(1, 15, 22), // "ScrollBarHRangeChanged" 103 | QT_MOC_LITERAL(2, 38, 0), // "" 104 | QT_MOC_LITERAL(3, 39, 3), // "min" 105 | QT_MOC_LITERAL(4, 43, 3), // "max" 106 | QT_MOC_LITERAL(5, 47, 22), // "ScrollBarVRangeChanged" 107 | QT_MOC_LITERAL(6, 70, 22), // "ScrollBarHValueChanged" 108 | QT_MOC_LITERAL(7, 93, 5), // "value" 109 | QT_MOC_LITERAL(8, 99, 22) // "ScrollBarVValueChanged" 110 | 111 | }, 112 | "CCompareWindow\0ScrollBarHRangeChanged\0" 113 | "\0min\0max\0ScrollBarVRangeChanged\0" 114 | "ScrollBarHValueChanged\0value\0" 115 | "ScrollBarVValueChanged" 116 | }; 117 | #undef QT_MOC_LITERAL 118 | 119 | static const uint qt_meta_data_CCompareWindow[] = { 120 | 121 | // content: 122 | 7, // revision 123 | 0, // classname 124 | 0, 0, // classinfo 125 | 4, 14, // methods 126 | 0, 0, // properties 127 | 0, 0, // enums/sets 128 | 0, 0, // constructors 129 | 0, // flags 130 | 0, // signalCount 131 | 132 | // slots: name, argc, parameters, tag, flags 133 | 1, 2, 34, 2, 0x08 /* Private */, 134 | 5, 2, 39, 2, 0x08 /* Private */, 135 | 6, 1, 44, 2, 0x08 /* Private */, 136 | 8, 1, 47, 2, 0x08 /* Private */, 137 | 138 | // slots: parameters 139 | QMetaType::Void, QMetaType::Int, QMetaType::Int, 3, 4, 140 | QMetaType::Void, QMetaType::Int, QMetaType::Int, 3, 4, 141 | QMetaType::Void, QMetaType::Int, 7, 142 | QMetaType::Void, QMetaType::Int, 7, 143 | 144 | 0 // eod 145 | }; 146 | 147 | void CCompareWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 148 | { 149 | if (_c == QMetaObject::InvokeMetaMethod) { 150 | CCompareWindow *_t = static_cast(_o); 151 | Q_UNUSED(_t) 152 | switch (_id) { 153 | case 0: _t->ScrollBarHRangeChanged((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; 154 | case 1: _t->ScrollBarVRangeChanged((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; 155 | case 2: _t->ScrollBarHValueChanged((*reinterpret_cast< int(*)>(_a[1]))); break; 156 | case 3: _t->ScrollBarVValueChanged((*reinterpret_cast< int(*)>(_a[1]))); break; 157 | default: ; 158 | } 159 | } 160 | } 161 | 162 | const QMetaObject CCompareWindow::staticMetaObject = { 163 | { &QWidget::staticMetaObject, qt_meta_stringdata_CCompareWindow.data, 164 | qt_meta_data_CCompareWindow, qt_static_metacall, Q_NULLPTR, Q_NULLPTR} 165 | }; 166 | 167 | 168 | const QMetaObject *CCompareWindow::metaObject() const 169 | { 170 | return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; 171 | } 172 | 173 | void *CCompareWindow::qt_metacast(const char *_clname) 174 | { 175 | if (!_clname) return Q_NULLPTR; 176 | if (!strcmp(_clname, qt_meta_stringdata_CCompareWindow.stringdata0)) 177 | return static_cast(const_cast< CCompareWindow*>(this)); 178 | if (!strcmp(_clname, "CBaseWindow")) 179 | return static_cast< CBaseWindow*>(const_cast< CCompareWindow*>(this)); 180 | return QWidget::qt_metacast(_clname); 181 | } 182 | 183 | int CCompareWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) 184 | { 185 | _id = QWidget::qt_metacall(_c, _id, _a); 186 | if (_id < 0) 187 | return _id; 188 | if (_c == QMetaObject::InvokeMetaMethod) { 189 | if (_id < 4) 190 | qt_static_metacall(this, _c, _id, _a); 191 | _id -= 4; 192 | } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { 193 | if (_id < 4) 194 | *reinterpret_cast(_a[0]) = -1; 195 | _id -= 4; 196 | } 197 | return _id; 198 | } 199 | QT_END_MOC_NAMESPACE 200 | -------------------------------------------------------------------------------- /moc_imageWindow.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Meta object code from reading C++ file 'imageWindow.h' 3 | ** 4 | ** Created by: The Qt Meta Object Compiler version 67 (Qt 5.7.0) 5 | ** 6 | ** WARNING! All changes made in this file will be lost! 7 | *****************************************************************************/ 8 | 9 | #include "stdafx.h" 10 | #include "imageWindow.h" 11 | #include 12 | #include 13 | #if !defined(Q_MOC_OUTPUT_REVISION) 14 | #error "The header file 'imageWindow.h' doesn't include ." 15 | #elif Q_MOC_OUTPUT_REVISION != 67 16 | #error "This file was generated using the moc from 5.7.0. It" 17 | #error "cannot be used with the include files from this version of Qt." 18 | #error "(The moc has changed too much.)" 19 | #endif 20 | 21 | QT_BEGIN_MOC_NAMESPACE 22 | struct qt_meta_stringdata_CImageLabel_t { 23 | QByteArrayData data[1]; 24 | char stringdata0[12]; 25 | }; 26 | #define QT_MOC_LITERAL(idx, ofs, len) \ 27 | Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ 28 | qptrdiff(offsetof(qt_meta_stringdata_CImageLabel_t, stringdata0) + ofs \ 29 | - idx * sizeof(QByteArrayData)) \ 30 | ) 31 | static const qt_meta_stringdata_CImageLabel_t qt_meta_stringdata_CImageLabel = { 32 | { 33 | QT_MOC_LITERAL(0, 0, 11) // "CImageLabel" 34 | 35 | }, 36 | "CImageLabel" 37 | }; 38 | #undef QT_MOC_LITERAL 39 | 40 | static const uint qt_meta_data_CImageLabel[] = { 41 | 42 | // content: 43 | 7, // revision 44 | 0, // classname 45 | 0, 0, // classinfo 46 | 0, 0, // methods 47 | 0, 0, // properties 48 | 0, 0, // enums/sets 49 | 0, 0, // constructors 50 | 0, // flags 51 | 0, // signalCount 52 | 53 | 0 // eod 54 | }; 55 | 56 | void CImageLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 57 | { 58 | Q_UNUSED(_o); 59 | Q_UNUSED(_id); 60 | Q_UNUSED(_c); 61 | Q_UNUSED(_a); 62 | } 63 | 64 | const QMetaObject CImageLabel::staticMetaObject = { 65 | { &QLabel::staticMetaObject, qt_meta_stringdata_CImageLabel.data, 66 | qt_meta_data_CImageLabel, qt_static_metacall, Q_NULLPTR, Q_NULLPTR} 67 | }; 68 | 69 | 70 | const QMetaObject *CImageLabel::metaObject() const 71 | { 72 | return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; 73 | } 74 | 75 | void *CImageLabel::qt_metacast(const char *_clname) 76 | { 77 | if (!_clname) return Q_NULLPTR; 78 | if (!strcmp(_clname, qt_meta_stringdata_CImageLabel.stringdata0)) 79 | return static_cast(const_cast< CImageLabel*>(this)); 80 | return QLabel::qt_metacast(_clname); 81 | } 82 | 83 | int CImageLabel::qt_metacall(QMetaObject::Call _c, int _id, void **_a) 84 | { 85 | _id = QLabel::qt_metacall(_c, _id, _a); 86 | if (_id < 0) 87 | return _id; 88 | return _id; 89 | } 90 | struct qt_meta_stringdata_CImageWindow_t { 91 | QByteArrayData data[1]; 92 | char stringdata0[13]; 93 | }; 94 | #define QT_MOC_LITERAL(idx, ofs, len) \ 95 | Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ 96 | qptrdiff(offsetof(qt_meta_stringdata_CImageWindow_t, stringdata0) + ofs \ 97 | - idx * sizeof(QByteArrayData)) \ 98 | ) 99 | static const qt_meta_stringdata_CImageWindow_t qt_meta_stringdata_CImageWindow = { 100 | { 101 | QT_MOC_LITERAL(0, 0, 12) // "CImageWindow" 102 | 103 | }, 104 | "CImageWindow" 105 | }; 106 | #undef QT_MOC_LITERAL 107 | 108 | static const uint qt_meta_data_CImageWindow[] = { 109 | 110 | // content: 111 | 7, // revision 112 | 0, // classname 113 | 0, 0, // classinfo 114 | 0, 0, // methods 115 | 0, 0, // properties 116 | 0, 0, // enums/sets 117 | 0, 0, // constructors 118 | 0, // flags 119 | 0, // signalCount 120 | 121 | 0 // eod 122 | }; 123 | 124 | void CImageWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 125 | { 126 | Q_UNUSED(_o); 127 | Q_UNUSED(_id); 128 | Q_UNUSED(_c); 129 | Q_UNUSED(_a); 130 | } 131 | 132 | const QMetaObject CImageWindow::staticMetaObject = { 133 | { &QScrollArea::staticMetaObject, qt_meta_stringdata_CImageWindow.data, 134 | qt_meta_data_CImageWindow, qt_static_metacall, Q_NULLPTR, Q_NULLPTR} 135 | }; 136 | 137 | 138 | const QMetaObject *CImageWindow::metaObject() const 139 | { 140 | return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; 141 | } 142 | 143 | void *CImageWindow::qt_metacast(const char *_clname) 144 | { 145 | if (!_clname) return Q_NULLPTR; 146 | if (!strcmp(_clname, qt_meta_stringdata_CImageWindow.stringdata0)) 147 | return static_cast(const_cast< CImageWindow*>(this)); 148 | if (!strcmp(_clname, "CBaseWindow")) 149 | return static_cast< CBaseWindow*>(const_cast< CImageWindow*>(this)); 150 | return QScrollArea::qt_metacast(_clname); 151 | } 152 | 153 | int CImageWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) 154 | { 155 | _id = QScrollArea::qt_metacall(_c, _id, _a); 156 | if (_id < 0) 157 | return _id; 158 | return _id; 159 | } 160 | QT_END_MOC_NAMESPACE 161 | -------------------------------------------------------------------------------- /moc_mainWindow.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** Meta object code from reading C++ file 'mainWindow.h' 3 | ** 4 | ** Created by: The Qt Meta Object Compiler version 67 (Qt 5.7.0) 5 | ** 6 | ** WARNING! All changes made in this file will be lost! 7 | *****************************************************************************/ 8 | 9 | #include "stdafx.h" 10 | #include "mainWindow.h" 11 | #include 12 | #include 13 | #if !defined(Q_MOC_OUTPUT_REVISION) 14 | #error "The header file 'mainWindow.h' doesn't include ." 15 | #elif Q_MOC_OUTPUT_REVISION != 67 16 | #error "This file was generated using the moc from 5.7.0. It" 17 | #error "cannot be used with the include files from this version of Qt." 18 | #error "(The moc has changed too much.)" 19 | #endif 20 | 21 | QT_BEGIN_MOC_NAMESPACE 22 | struct qt_meta_stringdata_CMainWindow_t { 23 | QByteArrayData data[23]; 24 | char stringdata0[235]; 25 | }; 26 | #define QT_MOC_LITERAL(idx, ofs, len) \ 27 | Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ 28 | qptrdiff(offsetof(qt_meta_stringdata_CMainWindow_t, stringdata0) + ofs \ 29 | - idx * sizeof(QByteArrayData)) \ 30 | ) 31 | static const qt_meta_stringdata_CMainWindow_t qt_meta_stringdata_CMainWindow = { 32 | { 33 | QT_MOC_LITERAL(0, 0, 11), // "CMainWindow" 34 | QT_MOC_LITERAL(1, 12, 4), // "Open" 35 | QT_MOC_LITERAL(2, 17, 0), // "" 36 | QT_MOC_LITERAL(3, 18, 7), // "Compare" 37 | QT_MOC_LITERAL(4, 26, 13), // "ReloadCurrent" 38 | QT_MOC_LITERAL(5, 40, 14), // "OpenRecentFile" 39 | QT_MOC_LITERAL(6, 55, 13), // "ChangeChannel" 40 | QT_MOC_LITERAL(7, 69, 7), // "channel" 41 | QT_MOC_LITERAL(8, 77, 10), // "ChangeFace" 42 | QT_MOC_LITERAL(9, 88, 4), // "face" 43 | QT_MOC_LITERAL(10, 93, 9), // "ChangeMip" 44 | QT_MOC_LITERAL(11, 103, 3), // "mip" 45 | QT_MOC_LITERAL(12, 107, 12), // "ChangeVisMin" 46 | QT_MOC_LITERAL(13, 120, 6), // "visMin" 47 | QT_MOC_LITERAL(14, 127, 12), // "ChangeVisMax" 48 | QT_MOC_LITERAL(15, 140, 6), // "visMax" 49 | QT_MOC_LITERAL(16, 147, 14), // "ChangeVisGamma" 50 | QT_MOC_LITERAL(17, 162, 8), // "visGamma" 51 | QT_MOC_LITERAL(18, 171, 17), // "ChangeVisDiffMult" 52 | QT_MOC_LITERAL(19, 189, 4), // "mult" 53 | QT_MOC_LITERAL(20, 194, 18), // "SubWindowActivated" 54 | QT_MOC_LITERAL(21, 213, 14), // "QMdiSubWindow*" 55 | QT_MOC_LITERAL(22, 228, 6) // "window" 56 | 57 | }, 58 | "CMainWindow\0Open\0\0Compare\0ReloadCurrent\0" 59 | "OpenRecentFile\0ChangeChannel\0channel\0" 60 | "ChangeFace\0face\0ChangeMip\0mip\0" 61 | "ChangeVisMin\0visMin\0ChangeVisMax\0" 62 | "visMax\0ChangeVisGamma\0visGamma\0" 63 | "ChangeVisDiffMult\0mult\0SubWindowActivated\0" 64 | "QMdiSubWindow*\0window" 65 | }; 66 | #undef QT_MOC_LITERAL 67 | 68 | static const uint qt_meta_data_CMainWindow[] = { 69 | 70 | // content: 71 | 7, // revision 72 | 0, // classname 73 | 0, 0, // classinfo 74 | 12, 14, // methods 75 | 0, 0, // properties 76 | 0, 0, // enums/sets 77 | 0, 0, // constructors 78 | 0, // flags 79 | 0, // signalCount 80 | 81 | // slots: name, argc, parameters, tag, flags 82 | 1, 0, 74, 2, 0x08 /* Private */, 83 | 3, 0, 75, 2, 0x08 /* Private */, 84 | 4, 0, 76, 2, 0x08 /* Private */, 85 | 5, 0, 77, 2, 0x08 /* Private */, 86 | 6, 1, 78, 2, 0x08 /* Private */, 87 | 8, 1, 81, 2, 0x08 /* Private */, 88 | 10, 1, 84, 2, 0x08 /* Private */, 89 | 12, 1, 87, 2, 0x08 /* Private */, 90 | 14, 1, 90, 2, 0x08 /* Private */, 91 | 16, 1, 93, 2, 0x08 /* Private */, 92 | 18, 1, 96, 2, 0x08 /* Private */, 93 | 20, 1, 99, 2, 0x08 /* Private */, 94 | 95 | // slots: parameters 96 | QMetaType::Void, 97 | QMetaType::Void, 98 | QMetaType::Void, 99 | QMetaType::Void, 100 | QMetaType::Void, QMetaType::Int, 7, 101 | QMetaType::Void, QMetaType::Int, 9, 102 | QMetaType::Void, QMetaType::Int, 11, 103 | QMetaType::Void, QMetaType::Float, 13, 104 | QMetaType::Void, QMetaType::Float, 15, 105 | QMetaType::Void, QMetaType::Float, 17, 106 | QMetaType::Void, QMetaType::Float, 19, 107 | QMetaType::Void, 0x80000000 | 21, 22, 108 | 109 | 0 // eod 110 | }; 111 | 112 | void CMainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 113 | { 114 | if (_c == QMetaObject::InvokeMetaMethod) { 115 | CMainWindow *_t = static_cast(_o); 116 | Q_UNUSED(_t) 117 | switch (_id) { 118 | case 0: _t->Open(); break; 119 | case 1: _t->Compare(); break; 120 | case 2: _t->ReloadCurrent(); break; 121 | case 3: _t->OpenRecentFile(); break; 122 | case 4: _t->ChangeChannel((*reinterpret_cast< int(*)>(_a[1]))); break; 123 | case 5: _t->ChangeFace((*reinterpret_cast< int(*)>(_a[1]))); break; 124 | case 6: _t->ChangeMip((*reinterpret_cast< int(*)>(_a[1]))); break; 125 | case 7: _t->ChangeVisMin((*reinterpret_cast< float(*)>(_a[1]))); break; 126 | case 8: _t->ChangeVisMax((*reinterpret_cast< float(*)>(_a[1]))); break; 127 | case 9: _t->ChangeVisGamma((*reinterpret_cast< float(*)>(_a[1]))); break; 128 | case 10: _t->ChangeVisDiffMult((*reinterpret_cast< float(*)>(_a[1]))); break; 129 | case 11: _t->SubWindowActivated((*reinterpret_cast< QMdiSubWindow*(*)>(_a[1]))); break; 130 | default: ; 131 | } 132 | } 133 | } 134 | 135 | const QMetaObject CMainWindow::staticMetaObject = { 136 | { &QMainWindow::staticMetaObject, qt_meta_stringdata_CMainWindow.data, 137 | qt_meta_data_CMainWindow, qt_static_metacall, Q_NULLPTR, Q_NULLPTR} 138 | }; 139 | 140 | 141 | const QMetaObject *CMainWindow::metaObject() const 142 | { 143 | return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; 144 | } 145 | 146 | void *CMainWindow::qt_metacast(const char *_clname) 147 | { 148 | if (!_clname) return Q_NULLPTR; 149 | if (!strcmp(_clname, qt_meta_stringdata_CMainWindow.stringdata0)) 150 | return static_cast(const_cast< CMainWindow*>(this)); 151 | return QMainWindow::qt_metacast(_clname); 152 | } 153 | 154 | int CMainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) 155 | { 156 | _id = QMainWindow::qt_metacall(_c, _id, _a); 157 | if (_id < 0) 158 | return _id; 159 | if (_c == QMetaObject::InvokeMetaMethod) { 160 | if (_id < 12) 161 | qt_static_metacall(this, _c, _id, _a); 162 | _id -= 12; 163 | } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { 164 | if (_id < 12) 165 | *reinterpret_cast(_a[0]) = -1; 166 | _id -= 12; 167 | } 168 | return _id; 169 | } 170 | QT_END_MOC_NAMESPACE 171 | -------------------------------------------------------------------------------- /readme/compare.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knarkowicz/ProgImgView/54c76f7fa7fb0bd80a0b7a9deafccdfa8f71f583/readme/compare.jpg -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "DirectXTex/DirectXTex/DirectXTex.h" 15 | #include 16 | #include "3rdparty/FreeImage/FreeImage.h" -------------------------------------------------------------------------------- /util.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "util.h" 3 | 4 | struct SFormatName 5 | { 6 | DXGI_FORMAT m_format; 7 | QString m_name; 8 | }; 9 | 10 | #define MAKE_FMT_DESC( x ) { DXGI_FORMAT_##x, #x } 11 | 12 | SFormatName GFormatNameArr[] = 13 | { 14 | MAKE_FMT_DESC( UNKNOWN ), 15 | MAKE_FMT_DESC( R32G32B32A32_TYPELESS ), 16 | MAKE_FMT_DESC( R32G32B32A32_FLOAT ), 17 | MAKE_FMT_DESC( R32G32B32A32_UINT ), 18 | MAKE_FMT_DESC( R32G32B32A32_SINT ), 19 | MAKE_FMT_DESC( R32G32B32_TYPELESS ), 20 | MAKE_FMT_DESC( R32G32B32_FLOAT ), 21 | MAKE_FMT_DESC( R32G32B32_UINT ), 22 | MAKE_FMT_DESC( R32G32B32_SINT ), 23 | MAKE_FMT_DESC( R16G16B16A16_TYPELESS ), 24 | MAKE_FMT_DESC( R16G16B16A16_FLOAT ), 25 | MAKE_FMT_DESC( R16G16B16A16_UNORM ), 26 | MAKE_FMT_DESC( R16G16B16A16_UINT ), 27 | MAKE_FMT_DESC( R16G16B16A16_SNORM ), 28 | MAKE_FMT_DESC( R16G16B16A16_SINT ), 29 | MAKE_FMT_DESC( R32G32_TYPELESS ), 30 | MAKE_FMT_DESC( R32G32_FLOAT ), 31 | MAKE_FMT_DESC( R32G32_UINT ), 32 | MAKE_FMT_DESC( R32G32_SINT ), 33 | MAKE_FMT_DESC( R32G8X24_TYPELESS ), 34 | MAKE_FMT_DESC( D32_FLOAT_S8X24_UINT ), 35 | MAKE_FMT_DESC( R32_FLOAT_X8X24_TYPELESS ), 36 | MAKE_FMT_DESC( X32_TYPELESS_G8X24_UINT ), 37 | MAKE_FMT_DESC( R10G10B10A2_TYPELESS ), 38 | MAKE_FMT_DESC( R10G10B10A2_UNORM ), 39 | MAKE_FMT_DESC( R10G10B10A2_UINT ), 40 | MAKE_FMT_DESC( R11G11B10_FLOAT ), 41 | MAKE_FMT_DESC( R8G8B8A8_TYPELESS ), 42 | MAKE_FMT_DESC( R8G8B8A8_UNORM ), 43 | MAKE_FMT_DESC( R8G8B8A8_UNORM_SRGB ), 44 | MAKE_FMT_DESC( R8G8B8A8_UINT ), 45 | MAKE_FMT_DESC( R8G8B8A8_SNORM ), 46 | MAKE_FMT_DESC( R8G8B8A8_SINT ), 47 | MAKE_FMT_DESC( R16G16_TYPELESS ), 48 | MAKE_FMT_DESC( R16G16_FLOAT ), 49 | MAKE_FMT_DESC( R16G16_UNORM ), 50 | MAKE_FMT_DESC( R16G16_UINT ), 51 | MAKE_FMT_DESC( R16G16_SNORM ), 52 | MAKE_FMT_DESC( R16G16_SINT ), 53 | MAKE_FMT_DESC( R32_TYPELESS ), 54 | MAKE_FMT_DESC( D32_FLOAT ), 55 | MAKE_FMT_DESC( R32_FLOAT ), 56 | MAKE_FMT_DESC( R32_UINT ), 57 | MAKE_FMT_DESC( R32_SINT ), 58 | MAKE_FMT_DESC( R24G8_TYPELESS ), 59 | MAKE_FMT_DESC( D24_UNORM_S8_UINT ), 60 | MAKE_FMT_DESC( R24_UNORM_X8_TYPELESS ), 61 | MAKE_FMT_DESC( X24_TYPELESS_G8_UINT ), 62 | MAKE_FMT_DESC( R8G8_TYPELESS ), 63 | MAKE_FMT_DESC( R8G8_UNORM ), 64 | MAKE_FMT_DESC( R8G8_UINT ), 65 | MAKE_FMT_DESC( R8G8_SNORM ), 66 | MAKE_FMT_DESC( R8G8_SINT ), 67 | MAKE_FMT_DESC( R16_TYPELESS ), 68 | MAKE_FMT_DESC( R16_FLOAT ), 69 | MAKE_FMT_DESC( D16_UNORM ), 70 | MAKE_FMT_DESC( R16_UNORM ), 71 | MAKE_FMT_DESC( R16_UINT ), 72 | MAKE_FMT_DESC( R16_SNORM ), 73 | MAKE_FMT_DESC( R16_SINT ), 74 | MAKE_FMT_DESC( R8_TYPELESS ), 75 | MAKE_FMT_DESC( R8_UNORM ), 76 | MAKE_FMT_DESC( R8_UINT ), 77 | MAKE_FMT_DESC( R8_SNORM ), 78 | MAKE_FMT_DESC( R8_SINT ), 79 | MAKE_FMT_DESC( A8_UNORM ), 80 | MAKE_FMT_DESC( R1_UNORM ), 81 | MAKE_FMT_DESC( R9G9B9E5_SHAREDEXP ), 82 | MAKE_FMT_DESC( R8G8_B8G8_UNORM ), 83 | MAKE_FMT_DESC( G8R8_G8B8_UNORM ), 84 | MAKE_FMT_DESC( BC1_TYPELESS ), 85 | MAKE_FMT_DESC( BC1_UNORM ), 86 | MAKE_FMT_DESC( BC1_UNORM_SRGB ), 87 | MAKE_FMT_DESC( BC2_TYPELESS ), 88 | MAKE_FMT_DESC( BC2_UNORM ), 89 | MAKE_FMT_DESC( BC2_UNORM_SRGB ), 90 | MAKE_FMT_DESC( BC3_TYPELESS ), 91 | MAKE_FMT_DESC( BC3_UNORM ), 92 | MAKE_FMT_DESC( BC3_UNORM_SRGB ), 93 | MAKE_FMT_DESC( BC4_TYPELESS ), 94 | MAKE_FMT_DESC( BC4_UNORM ), 95 | MAKE_FMT_DESC( BC4_SNORM ), 96 | MAKE_FMT_DESC( BC5_TYPELESS ), 97 | MAKE_FMT_DESC( BC5_UNORM ), 98 | MAKE_FMT_DESC( BC5_SNORM ), 99 | MAKE_FMT_DESC( B5G6R5_UNORM ), 100 | MAKE_FMT_DESC( B5G5R5A1_UNORM ), 101 | MAKE_FMT_DESC( B8G8R8A8_UNORM ), 102 | MAKE_FMT_DESC( B8G8R8X8_UNORM ), 103 | MAKE_FMT_DESC( R10G10B10_XR_BIAS_A2_UNORM ), 104 | MAKE_FMT_DESC( B8G8R8A8_TYPELESS ), 105 | MAKE_FMT_DESC( B8G8R8A8_UNORM_SRGB ), 106 | MAKE_FMT_DESC( B8G8R8X8_TYPELESS ), 107 | MAKE_FMT_DESC( B8G8R8X8_UNORM_SRGB ), 108 | MAKE_FMT_DESC( BC6H_TYPELESS ), 109 | MAKE_FMT_DESC( BC6H_UF16 ), 110 | MAKE_FMT_DESC( BC6H_SF16 ), 111 | MAKE_FMT_DESC( BC7_TYPELESS ), 112 | MAKE_FMT_DESC( BC7_UNORM ), 113 | MAKE_FMT_DESC( BC7_UNORM_SRGB ), 114 | MAKE_FMT_DESC( FORCE_UINT ), 115 | }; 116 | 117 | bool UtilLoadFile( DirectX::ScratchImage& scratchImage, DirectX::TexMetadata& info, QString& formatName, QString& fileName, unsigned& texelSizeInBytes, QString const& path ) 118 | { 119 | wchar_t pathW[ MAX_PATH ]; 120 | path.toWCharArray( pathW ); 121 | pathW[ path.length() ] = 0; 122 | 123 | HRESULT hr = DirectX::LoadFromDDSFile( pathW, 0, &info, scratchImage ); 124 | if ( hr != S_OK ) 125 | { 126 | hr = DirectX::LoadFromTGAFile( pathW, &info, scratchImage ); 127 | } 128 | if ( hr != S_OK ) 129 | { 130 | hr = DirectX::LoadFromWICFile( pathW, 0, &info, scratchImage ); 131 | } 132 | if ( hr != S_OK ) 133 | { 134 | hr = DirectX::LoadFromHDRFile( pathW, &info, scratchImage ); 135 | } 136 | if ( hr != S_OK ) 137 | { 138 | FIBITMAP* dib = FreeImage_Load( FIF_HDR, path.toLatin1(), HDR_DEFAULT ); 139 | if ( !dib ) 140 | { 141 | dib = FreeImage_Load( FIF_EXR, path.toLatin1(), EXR_DEFAULT ); 142 | } 143 | 144 | if ( dib ) 145 | { 146 | info.arraySize = 1; 147 | info.depth = 1; 148 | info.dimension = DirectX::TEX_DIMENSION_TEXTURE2D; 149 | info.format = DXGI_FORMAT_UNKNOWN; 150 | info.width = FreeImage_GetWidth( dib ); 151 | info.height = FreeImage_GetHeight( dib ); 152 | info.mipLevels = 1; 153 | 154 | unsigned const bpp = FreeImage_GetBPP( dib ); 155 | if ( bpp == 128 ) 156 | { 157 | info.format = DXGI_FORMAT_R32G32B32A32_FLOAT; 158 | } 159 | else if ( bpp == 96 ) 160 | { 161 | info.format = DXGI_FORMAT_R32G32B32_FLOAT; 162 | } 163 | else if ( bpp == 64 ) 164 | { 165 | info.format = DXGI_FORMAT_R16G16B16A16_FLOAT; 166 | } 167 | 168 | if ( info.format != DXGI_FORMAT_UNKNOWN ) 169 | { 170 | FreeImage_FlipVertical( dib ); 171 | scratchImage.Initialize2D( info.format, info.width, info.height, 1, 1, 0 ); 172 | 173 | uint8_t* srcPixels = FreeImage_GetBits( dib ); 174 | texelSizeInBytes = DirectX::BitsPerPixel( info.format ) / 8; 175 | memcpy( scratchImage.GetPixels(), srcPixels, info.width * info.height * texelSizeInBytes ); 176 | 177 | hr = S_OK; 178 | } 179 | FreeImage_Unload( dib ); 180 | } 181 | } 182 | 183 | if ( hr != S_OK ) 184 | { 185 | QMessageBox::critical( nullptr, "Error", "Can't load image: " + path ); 186 | return false; 187 | } 188 | 189 | formatName = "???"; 190 | for ( unsigned i = 0; i < ARRAYSIZE( GFormatNameArr ); ++i ) 191 | { 192 | if ( GFormatNameArr[ i ].m_format == info.format ) 193 | { 194 | formatName = GFormatNameArr[ i ].m_name; 195 | break; 196 | } 197 | } 198 | 199 | if ( DirectX::IsCompressed( info.format ) ) 200 | { 201 | DirectX::ScratchImage decompressedImage; 202 | hr = DirectX::Decompress( scratchImage.GetImages(), scratchImage.GetImageCount(), info, DXGI_FORMAT_UNKNOWN, decompressedImage ); 203 | assert( hr == S_OK ); 204 | scratchImage = std::move( decompressedImage ); 205 | info = scratchImage.GetMetadata(); 206 | } 207 | 208 | info.arraySize = std::max( 1, info.arraySize ); 209 | info.mipLevels = std::max( 1, info.mipLevels ); 210 | 211 | fileName = path.mid( path.lastIndexOf( '/' ) + 1 ); 212 | texelSizeInBytes = DirectX::BitsPerPixel( info.format ) / 8; 213 | return true; 214 | } -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool UtilLoadFile( DirectX::ScratchImage& scratchImage, DirectX::TexMetadata& info, QString& formatName, QString& fileName, unsigned& texelSizeInBytes, QString const& path ); 4 | 5 | inline float ClampF( float v, float minV, float maxV ) 6 | { 7 | return std::min( std::max( v, minV ), maxV ); 8 | } 9 | 10 | inline float ClampZoom( float v ) 11 | { 12 | float const zoomMin = 1.0f / 8.0f; 13 | float const zoomMax = 32.0f; 14 | float z = std::min( std::max( v, zoomMin ), zoomMax ); 15 | z = z > 1.0f ? floorf( z ) : 1.0f / ceilf( 1.0f / z ); 16 | return z; 17 | } 18 | 19 | inline void HalfToFloat( float* dst, void const* src, unsigned num ) 20 | { 21 | DirectX::PackedVector::XMConvertHalfToFloatStream( dst, 4, (DirectX::PackedVector::HALF const*) src, 2, num ); 22 | } 23 | 24 | inline void ReadR8_UNorm( float texel[ 4 ], uint8_t *& srcPtr ) 25 | { 26 | texel[ 0 ] = srcPtr[ 0 ] / 255.0f; 27 | texel[ 1 ] = srcPtr[ 0 ] / 255.0f; 28 | texel[ 2 ] = srcPtr[ 0 ] / 255.0f; 29 | texel[ 3 ] = srcPtr[ 0 ] / 255.0f; 30 | srcPtr += 1; 31 | } 32 | 33 | inline void ReadR8G8_UNorm( float texel[ 4 ], uint8_t *& srcPtr ) 34 | { 35 | texel[ 0 ] = srcPtr[ 0 ] / 255.0f; 36 | texel[ 1 ] = srcPtr[ 1 ] / 255.0f; 37 | texel[ 2 ] = 0.0f; 38 | texel[ 3 ] = 0.0f; 39 | srcPtr += 2; 40 | } 41 | 42 | inline void ReadR8G8_SNorm( float texel[ 4 ], uint8_t *& srcPtr ) 43 | { 44 | int8_t valXSInt = *( (int8_t*) srcPtr + 0 ); 45 | int8_t valYSInt = *( (int8_t*) srcPtr + 1 ); 46 | float sintMax = INT8_MAX; 47 | float sintMin = INT8_MIN; 48 | 49 | texel[ 0 ] = valXSInt > 0 ? ( valXSInt / sintMax ) : ( valXSInt / sintMax ); 50 | texel[ 1 ] = valYSInt > 0 ? ( valYSInt / sintMin ) : ( valYSInt / sintMin ); 51 | texel[ 2 ] = 0.0f; 52 | texel[ 3 ] = 0.0f; 53 | srcPtr += 2; 54 | } 55 | 56 | inline void ReadB8G8R8A8_UNorm( float texel[ 4 ], uint8_t *& srcPtr ) 57 | { 58 | texel[ 0 ] = srcPtr[ 2 ] / 255.0f; 59 | texel[ 1 ] = srcPtr[ 1 ] / 255.0f; 60 | texel[ 2 ] = srcPtr[ 0 ] / 255.0f; 61 | texel[ 3 ] = srcPtr[ 3 ] / 255.0f; 62 | srcPtr += 4; 63 | } 64 | 65 | inline void ReadB8G8R8X8_UNorm( float texel[ 4 ], uint8_t *& srcPtr ) 66 | { 67 | texel[ 0 ] = srcPtr[ 2 ] / 255.0f; 68 | texel[ 1 ] = srcPtr[ 1 ] / 255.0f; 69 | texel[ 2 ] = srcPtr[ 0 ] / 255.0f; 70 | texel[ 3 ] = 1.0f; 71 | srcPtr += 4; 72 | } 73 | 74 | inline void ReadR8G8B8A8_UNorm( float texel[ 4 ], uint8_t *& srcPtr ) 75 | { 76 | texel[ 0 ] = srcPtr[ 0 ] / 255.0f; 77 | texel[ 1 ] = srcPtr[ 1 ] / 255.0f; 78 | texel[ 2 ] = srcPtr[ 2 ] / 255.0f; 79 | texel[ 3 ] = srcPtr[ 3 ] / 255.0f; 80 | srcPtr += 4; 81 | } 82 | 83 | inline void ReadD16_UNorm( float texel[ 4 ], uint8_t *& srcPtr ) 84 | { 85 | uint16_t val; 86 | memcpy( &val, srcPtr, sizeof( val ) ); 87 | 88 | texel[ 0 ] = val / float( UINT16_MAX ); 89 | texel[ 1 ] = val / float( UINT16_MAX ); 90 | texel[ 2 ] = val / float( UINT16_MAX ); 91 | texel[ 3 ] = val / float( UINT16_MAX ); 92 | 93 | srcPtr += 2; 94 | } 95 | 96 | inline void ReadR10G10B10A2_UNorm( float texel[ 4 ], uint8_t *& srcPtr ) 97 | { 98 | unsigned val; 99 | memcpy( &val, srcPtr, sizeof( val ) ); 100 | unsigned const valRUint = val & 0x000003FF; 101 | unsigned const valGUint = ( val >> 10 ) & 0x000003FF; 102 | unsigned const valBUint = ( val >> 20 ) & 0x000003FF; 103 | unsigned const valAUint = val >> 30; 104 | 105 | texel[ 0 ] = valRUint / 1023.0f; 106 | texel[ 1 ] = valGUint / 1023.0f; 107 | texel[ 2 ] = valBUint / 1023.0f; 108 | texel[ 3 ] = valAUint / 3.0f; 109 | 110 | srcPtr += 4; 111 | } 112 | 113 | inline void ReadR11G11B10_Float( float texel[ 4 ], uint8_t *& srcPtr ) 114 | { 115 | DirectX::PackedVector::XMFLOAT3PK const tmp3PK( *( (uint32_t*) srcPtr ) ); 116 | DirectX::XMVECTOR tmpV = DirectX::PackedVector::XMLoadFloat3PK( &tmp3PK ); 117 | DirectX::XMStoreFloat4( (DirectX::XMFLOAT4*) texel, tmpV ); 118 | 119 | srcPtr += 4; 120 | } 121 | 122 | inline void ReadR16G16_Float( float texel[ 4 ], uint8_t *& srcPtr ) 123 | { 124 | HalfToFloat( texel, srcPtr, 2 ); 125 | srcPtr += 4; 126 | } 127 | 128 | inline void ReadR16G16B16A16_UNorm( float texel[ 4 ], uint8_t *& srcPtr ) 129 | { 130 | uint16_t valU16[ 4 ]; 131 | memcpy( &valU16, srcPtr, sizeof( valU16 ) ); 132 | 133 | texel[ 0 ] = valU16[ 0 ] / float( UINT16_MAX ); 134 | texel[ 1 ] = valU16[ 1 ] / float( UINT16_MAX ); 135 | texel[ 2 ] = valU16[ 2 ] / float( UINT16_MAX ); 136 | texel[ 3 ] = valU16[ 3 ] / float( UINT16_MAX ); 137 | srcPtr += 8; 138 | } 139 | 140 | inline void ReadR16G16B16A16_Float( float texel[ 4 ], uint8_t *& srcPtr ) 141 | { 142 | HalfToFloat( texel, srcPtr, 4 ); 143 | srcPtr += 8; 144 | } 145 | 146 | inline void ReadR32G32B32_Float( float texel[ 4 ], uint8_t *& srcPtr ) 147 | { 148 | memcpy( texel, srcPtr, 3 * sizeof( float ) ); 149 | texel[ 3 ] = 1.0f; 150 | srcPtr += 12; 151 | } 152 | 153 | inline void ReadR32G32B32A32_Float( float texel[ 4 ], uint8_t *& srcPtr ) 154 | { 155 | memcpy( texel, srcPtr, 4 * sizeof( float ) ); 156 | srcPtr += 16; 157 | } 158 | 159 | inline void ReadR32G32B32A32_UInt( float texel[ 4 ], uint8_t *& srcPtr ) 160 | { 161 | texel[ 0 ] = *( (uint32_t*) srcPtr + 0 ); 162 | texel[ 1 ] = *( (uint32_t*) srcPtr + 1 ); 163 | texel[ 2 ] = *( (uint32_t*) srcPtr + 2 ); 164 | texel[ 3 ] = *( (uint32_t*) srcPtr + 3 ); 165 | 166 | srcPtr += 16; 167 | } 168 | 169 | inline void ReadR32G32B32A32_SInt( float texel[ 4 ], uint8_t *& srcPtr ) 170 | { 171 | texel[ 0 ] = *( (int32_t*) srcPtr + 0 ); 172 | texel[ 1 ] = *( (int32_t*) srcPtr + 1 ); 173 | texel[ 2 ] = *( (int32_t*) srcPtr + 2 ); 174 | texel[ 3 ] = *( (int32_t*) srcPtr + 3 ); 175 | 176 | srcPtr += 16; 177 | } 178 | 179 | inline void ReadR32_UInt( float texel[ 4 ], uint8_t *& srcPtr ) 180 | { 181 | texel[ 0 ] = *( (uint32_t*) srcPtr ); 182 | texel[ 1 ] = *( (uint32_t*) srcPtr ); 183 | texel[ 2 ] = *( (uint32_t*) srcPtr ); 184 | texel[ 3 ] = *( (uint32_t*) srcPtr ); 185 | 186 | srcPtr += 4; 187 | } 188 | 189 | inline void ReadR32_SInt( float texel[ 4 ], uint8_t *& srcPtr ) 190 | { 191 | texel[ 0 ] = *( (uint32_t*) srcPtr ); 192 | texel[ 1 ] = *( (uint32_t*) srcPtr ); 193 | texel[ 2 ] = *( (uint32_t*) srcPtr ); 194 | texel[ 3 ] = *( (uint32_t*) srcPtr ); 195 | 196 | srcPtr += 4; 197 | } 198 | 199 | inline void ReadR32_Float( float texel[ 4 ], uint8_t *& srcPtr ) 200 | { 201 | memcpy( texel, srcPtr, sizeof( float ) ); 202 | texel[ 1 ] = texel[ 0 ]; 203 | texel[ 2 ] = texel[ 0 ]; 204 | texel[ 3 ] = texel[ 0 ]; 205 | 206 | srcPtr += 4; 207 | } 208 | 209 | inline void ReadR16_Float( float texel[ 4 ], uint8_t *& srcPtr ) 210 | { 211 | HalfToFloat( texel, srcPtr, 1 ); 212 | texel[ 1 ] = texel[ 0 ]; 213 | texel[ 2 ] = texel[ 0 ]; 214 | texel[ 3 ] = texel[ 0 ]; 215 | 216 | srcPtr += 2; 217 | } 218 | 219 | inline void ReadR24G8_UInt( float texel[ 4 ], uint8_t *& srcPtr ) 220 | { 221 | unsigned const valRUint = srcPtr[ 0 ] + ( srcPtr[ 1 ] << 8 ) + ( srcPtr[ 2 ] << 16 ); 222 | 223 | texel[ 0 ] = valRUint / 16777216.0f; 224 | texel[ 1 ] = srcPtr[ 3 ] / 255.0f; 225 | texel[ 2 ] = 0.0f; 226 | texel[ 3 ] = 0.0f; 227 | 228 | srcPtr += 4; 229 | } 230 | 231 | inline void ReadR32S8( float texel[ 4 ], uint8_t *& srcPtr ) 232 | { 233 | float d32f; 234 | uint8_t stencil; 235 | memcpy( &d32f, srcPtr + 0, sizeof( float ) ); 236 | memcpy( &stencil, srcPtr + 4, sizeof( uint8_t ) ); 237 | 238 | texel[ 0 ] = d32f; 239 | texel[ 1 ] = stencil / 255.0f; 240 | texel[ 2 ] = 0.0f; 241 | texel[ 3 ] = 0.0f; 242 | 243 | srcPtr += 8; 244 | } 245 | 246 | inline void TexelInfoR8_UNorm( QString info[ 4 ], uint8_t const* srcPtr ) 247 | { 248 | unsigned const valUInt = srcPtr[ 0 ]; 249 | float const valFloat = valUInt / 255.0f; 250 | info[ 0 ] = QString( "%1(%2)" ).arg( valUInt ).arg( valFloat ); 251 | } 252 | 253 | inline void TexelInfoR8G8_UNorm( QString info[ 4 ], uint8_t const* srcPtr ) 254 | { 255 | unsigned const valXUInt = srcPtr[ 0 ]; 256 | unsigned const valYUInt = srcPtr[ 1 ]; 257 | float const valXFloat = valXUInt / 255.0f; 258 | float const valYFloat = valYUInt / 255.0f; 259 | 260 | info[ 0 ] = QString( "%1(%2)" ).arg( valXUInt ).arg( valXFloat ); 261 | info[ 1 ] = QString( "%1(%2)" ).arg( valYUInt ).arg( valYFloat ); 262 | } 263 | 264 | inline void TexelInfoR8G8_SNorm( QString info[ 4 ], uint8_t const* srcPtr ) 265 | { 266 | int8_t valXSInt = *( (int8_t*) srcPtr + 0 ); 267 | int8_t valYSInt = *( (int8_t*) srcPtr + 1 ); 268 | 269 | float sintMax = +INT8_MAX; 270 | float sintMin = -INT8_MIN; 271 | 272 | float valXFloat = valXSInt > 0 ? ( valXSInt / sintMax ) : ( valXSInt / sintMax ); 273 | float valYFloat = valYSInt > 0 ? ( valYSInt / sintMin ) : ( valYSInt / sintMin ); 274 | info[ 0 ] = QString( "%1(%2)" ).arg( valXSInt ).arg( valXFloat ); 275 | info[ 1 ] = QString( "%1(%2)" ).arg( valYSInt ).arg( valYFloat ); 276 | } 277 | 278 | inline void TexelInfoB8G8R8A8_UNorm( QString info[ 4 ], uint8_t const* srcPtr ) 279 | { 280 | unsigned const valRUint = srcPtr[ 2 ]; 281 | unsigned const valGUint = srcPtr[ 1 ]; 282 | unsigned const valBUint = srcPtr[ 0 ]; 283 | unsigned const valAUint = srcPtr[ 3 ]; 284 | float const valRFloat = valRUint / 255.0f; 285 | float const valGFloat = valGUint / 255.0f; 286 | float const valBFloat = valBUint / 255.0f; 287 | float const valAFloat = valAUint / 255.0f; 288 | 289 | info[ 0 ] = QString( "%1(%2)" ).arg( valRUint ).arg( valRFloat ); 290 | info[ 1 ] = QString( "%1(%2)" ).arg( valGUint ).arg( valGFloat ); 291 | info[ 2 ] = QString( "%1(%2)" ).arg( valBUint ).arg( valBFloat ); 292 | info[ 3 ] = QString( "%1(%2)" ).arg( valAUint ).arg( valAFloat ); 293 | } 294 | 295 | inline void TexelInfoB8G8R8X8_UNorm( QString info[ 4 ], uint8_t const* srcPtr ) 296 | { 297 | unsigned const valRUint = srcPtr[ 2 ]; 298 | unsigned const valGUint = srcPtr[ 1 ]; 299 | unsigned const valBUint = srcPtr[ 0 ]; 300 | float const valRFloat = valRUint / 255.0f; 301 | float const valGFloat = valGUint / 255.0f; 302 | float const valBFloat = valBUint / 255.0f; 303 | 304 | info[ 0 ] = QString( "%1(%2)" ).arg( valRUint ).arg( valRFloat ); 305 | info[ 1 ] = QString( "%1(%2)" ).arg( valGUint ).arg( valGFloat ); 306 | info[ 2 ] = QString( "%1(%2)" ).arg( valBUint ).arg( valBFloat ); 307 | } 308 | 309 | inline void TexelInfoR8G8B8A8_UNorm( QString info[ 4 ], uint8_t const* srcPtr ) 310 | { 311 | unsigned const valRUint = srcPtr[ 0 ]; 312 | unsigned const valGUint = srcPtr[ 1 ]; 313 | unsigned const valBUint = srcPtr[ 2 ]; 314 | unsigned const valAUint = srcPtr[ 3 ]; 315 | float const valRFloat = valRUint / 255.0f; 316 | float const valGFloat = valGUint / 255.0f; 317 | float const valBFloat = valBUint / 255.0f; 318 | float const valAFloat = valAUint / 255.0f; 319 | 320 | info[ 0 ] = QString( "%1(%2)" ).arg( valRUint ).arg( valRFloat ); 321 | info[ 1 ] = QString( "%1(%2)" ).arg( valGUint ).arg( valGFloat ); 322 | info[ 2 ] = QString( "%1(%2)" ).arg( valBUint ).arg( valBFloat ); 323 | info[ 3 ] = QString( "%1(%2)" ).arg( valAUint ).arg( valAFloat ); 324 | } 325 | 326 | inline void TexelInfoD16_UNorm( QString info[ 4 ], uint8_t const* srcPtr ) 327 | { 328 | uint16_t valU16; 329 | float valF; 330 | memcpy( &valU16, srcPtr, sizeof( valU16 ) ); 331 | valF = valU16 / float( UINT16_MAX ); 332 | 333 | info[ 0 ] = QString( "%1(%2)" ).arg( valF ).arg( valU16 ); 334 | } 335 | 336 | inline void TexelInfoR10G10B10A2_UNorm( QString info[ 4 ], uint8_t const* srcPtr ) 337 | { 338 | unsigned texel; 339 | memcpy( &texel, srcPtr, sizeof( texel ) ); 340 | unsigned const valRUint = texel & 0x000003FF; 341 | unsigned const valGUint = ( texel >> 10 ) & 0x000003FF; 342 | unsigned const valBUint = ( texel >> 20 ) & 0x000003FF; 343 | unsigned const valAUint = texel >> 30; 344 | float const valRFloat = valRUint / 1023.0f; 345 | float const valGFloat = valGUint / 1023.0f; 346 | float const valBFloat = valBUint / 1023.0f; 347 | float const valAFloat = valAUint / 3.0f; 348 | 349 | info[ 0 ] = QString( "%1(%2)" ).arg( valRUint ).arg( valRFloat ); 350 | info[ 1 ] = QString( "%1(%2)" ).arg( valGUint ).arg( valGFloat ); 351 | info[ 2 ] = QString( "%1(%2)" ).arg( valBUint ).arg( valBFloat ); 352 | info[ 3 ] = QString( "%1(%2)" ).arg( valAUint ).arg( valAFloat ); 353 | } 354 | 355 | inline void TexelInfoR11G11B10_Float( QString info[ 4 ], uint8_t const* srcPtr ) 356 | { 357 | DirectX::XMFLOAT4 val; 358 | 359 | DirectX::PackedVector::XMFLOAT3PK const tmp3PK( *( (uint32_t*) srcPtr ) ); 360 | DirectX::XMVECTOR tmpV = DirectX::PackedVector::XMLoadFloat3PK( &tmp3PK ); 361 | DirectX::XMStoreFloat4( &val, tmpV ); 362 | 363 | info[ 0 ] = QString( "%1" ).arg( val.x ); 364 | info[ 1 ] = QString( "%1" ).arg( val.y ); 365 | info[ 2 ] = QString( "%1" ).arg( val.z ); 366 | } 367 | 368 | inline void TexelInfoR16G16_Float( QString info[ 4 ], uint8_t const* srcPtr ) 369 | { 370 | float val[ 2 ]; 371 | HalfToFloat( val, srcPtr, ARRAYSIZE( val ) ); 372 | 373 | info[ 0 ] = QString( "%1" ).arg( val[ 0 ] ); 374 | info[ 1 ] = QString( "%1" ).arg( val[ 1 ] ); 375 | } 376 | 377 | inline void TexelInfoR16G16B16A16_UNorm( QString info[ 4 ], uint8_t const* srcPtr ) 378 | { 379 | uint16_t valU16[ 4 ]; 380 | memcpy( &valU16, srcPtr, sizeof( valU16 ) ); 381 | 382 | float val[ 4 ]; 383 | val[ 0 ] = valU16[ 0 ] / float( UINT16_MAX ); 384 | val[ 1 ] = valU16[ 1 ] / float( UINT16_MAX ); 385 | val[ 2 ] = valU16[ 2 ] / float( UINT16_MAX ); 386 | val[ 3 ] = valU16[ 3 ] / float( UINT16_MAX ); 387 | 388 | info[ 0 ] = QString( "%1(%2)" ).arg( val[ 0 ] ).arg( valU16[ 0 ] ); 389 | info[ 1 ] = QString( "%1(%2)" ).arg( val[ 1 ] ).arg( valU16[ 1 ] ); 390 | info[ 2 ] = QString( "%1(%2)" ).arg( val[ 2 ] ).arg( valU16[ 2 ] ); 391 | info[ 3 ] = QString( "%1(%2)" ).arg( val[ 3 ] ).arg( valU16[ 3 ] ); 392 | } 393 | 394 | inline void TexelInfoR16G16B16A16_Float( QString info[ 4 ], uint8_t const* srcPtr ) 395 | { 396 | float val[ 4 ]; 397 | HalfToFloat( val, srcPtr, ARRAYSIZE( val ) ); 398 | 399 | info[ 0 ] = QString( "%1" ).arg( val[ 0 ] ); 400 | info[ 1 ] = QString( "%1" ).arg( val[ 1 ] ); 401 | info[ 2 ] = QString( "%1" ).arg( val[ 2 ] ); 402 | info[ 3 ] = QString( "%1" ).arg( val[ 3 ] ); 403 | } 404 | 405 | inline void TexelInfoR32G32B32_Float( QString info[ 4 ], uint8_t const* srcPtr ) 406 | { 407 | float val[ 3 ]; 408 | memcpy( &val, srcPtr, sizeof( val ) ); 409 | 410 | info[ 0 ] = QString( "%1" ).arg( val[ 0 ] ); 411 | info[ 1 ] = QString( "%1" ).arg( val[ 1 ] ); 412 | info[ 2 ] = QString( "%1" ).arg( val[ 2 ] ); 413 | } 414 | 415 | inline void TexelInfoR32G32B32A32_Float( QString info[ 4 ], uint8_t const* srcPtr ) 416 | { 417 | float val[ 4 ]; 418 | memcpy( &val, srcPtr, sizeof( val ) ); 419 | 420 | info[ 0 ] = QString( "%1" ).arg( val[ 0 ] ); 421 | info[ 1 ] = QString( "%1" ).arg( val[ 1 ] ); 422 | info[ 2 ] = QString( "%1" ).arg( val[ 2 ] ); 423 | info[ 3 ] = QString( "%1" ).arg( val[ 3 ] ); 424 | } 425 | 426 | inline void TexelInfoR32G32B32A32_UInt( QString info[ 4 ], uint8_t const* srcPtr ) 427 | { 428 | uint32_t val[ 4 ]; 429 | val[ 0 ] = *( (uint32_t*) srcPtr + 0 ); 430 | val[ 1 ] = *( (uint32_t*) srcPtr + 1 ); 431 | val[ 2 ] = *( (uint32_t*) srcPtr + 2 ); 432 | val[ 3 ] = *( (uint32_t*) srcPtr + 3 ); 433 | 434 | info[ 0 ] = QString( "%1(0x%2)" ).arg( val[ 0 ] ).arg( val[ 0 ], 0, 16 ); 435 | info[ 1 ] = QString( "%1(0x%2)" ).arg( val[ 1 ] ).arg( val[ 1 ], 0, 16 ); 436 | info[ 2 ] = QString( "%1(0x%2)" ).arg( val[ 2 ] ).arg( val[ 2 ], 0, 16 ); 437 | info[ 3 ] = QString( "%1(0x%2)" ).arg( val[ 3 ] ).arg( val[ 3 ], 0, 16 ); 438 | } 439 | 440 | inline void TexelInfoR32G32B32A32_SInt( QString info[ 4 ], uint8_t const* srcPtr ) 441 | { 442 | int32_t val[ 4 ]; 443 | val[ 0 ] = *( (int32_t*) srcPtr + 0 ); 444 | val[ 1 ] = *( (int32_t*) srcPtr + 1 ); 445 | val[ 2 ] = *( (int32_t*) srcPtr + 2 ); 446 | val[ 3 ] = *( (int32_t*) srcPtr + 3 ); 447 | 448 | info[ 0 ] = QString( "%1(0x%2)" ).arg( val[ 0 ] ).arg( val[ 0 ], 0, 16 ); 449 | info[ 1 ] = QString( "%1(0x%2)" ).arg( val[ 1 ] ).arg( val[ 1 ], 0, 16 ); 450 | info[ 2 ] = QString( "%1(0x%2)" ).arg( val[ 2 ] ).arg( val[ 2 ], 0, 16 ); 451 | info[ 3 ] = QString( "%1(0x%2)" ).arg( val[ 3 ] ).arg( val[ 3 ], 0, 16 ); 452 | } 453 | 454 | inline void TexelInfoR32_UInt( QString info[ 4 ], uint8_t const* srcPtr ) 455 | { 456 | uint32_t val = *( (uint32_t*) srcPtr ); 457 | info[ 0 ] = QString( "%1(0x%2)" ).arg( val ).arg( val, 0, 16 ); 458 | } 459 | 460 | inline void TexelInfoR32_SInt( QString info[ 4 ], uint8_t const* srcPtr ) 461 | { 462 | int32_t val = *( (int32_t*) srcPtr ); 463 | info[ 0 ] = QString( "%1(0x%2)" ).arg( val ).arg( val, 0, 16 ); 464 | } 465 | 466 | inline void TexelInfoR32_Float( QString info[ 4 ], uint8_t const* srcPtr ) 467 | { 468 | float val; 469 | memcpy( &val, srcPtr, sizeof( float ) ); 470 | info[ 0 ] = QString( "%1" ).arg( val ); 471 | } 472 | 473 | inline void TexelInfoR16_Float( QString info[ 4 ], uint8_t const* srcPtr ) 474 | { 475 | float val; 476 | HalfToFloat( &val, srcPtr, 1 ); 477 | info[ 0 ] = QString( "%1" ).arg( val ); 478 | } 479 | 480 | inline void TexelInfoR24G8_UInt( QString info[ 4 ], uint8_t const* srcPtr ) 481 | { 482 | unsigned const valRUint = srcPtr[ 0 ] + ( srcPtr[ 1 ] << 8 ) + ( srcPtr[ 2 ] << 16 ); 483 | unsigned const valGUint = srcPtr[ 3 ]; 484 | float const valRFloat = valRUint / 16777216.0f; 485 | float const valGFloat = valGUint / 255.0f; 486 | info[ 0 ] = QString( "%1(%2)" ).arg( valRUint ).arg( valRFloat ); 487 | info[ 1 ] = QString( "%1(%2)" ).arg( valGUint ).arg( valGFloat ); 488 | } 489 | 490 | inline void TexelInfoR32S8( QString info[ 4 ], uint8_t const* srcPtr ) 491 | { 492 | float d32f; 493 | uint8_t stencil; 494 | memcpy( &d32f, srcPtr + 0, sizeof( float ) ); 495 | memcpy( &stencil, srcPtr + 4, sizeof( uint8_t ) ); 496 | 497 | info[ 0 ] = QString( "%1" ).arg( d32f ); 498 | info[ 1 ] = QString( "%1(%2)" ).arg( stencil ).arg( stencil / 255.0f ); 499 | } --------------------------------------------------------------------------------