├── .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 | 
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 | }
--------------------------------------------------------------------------------