]> git.cworth.org Git - vogl/blob - src/vogleditor/vogleditor_qtextureviewer.cpp
Initial vogl checkin
[vogl] / src / vogleditor / vogleditor_qtextureviewer.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 #include <QtGui>
27 #include "vogleditor_qtextureviewer.h"
28 #include "vogl_buffer_stream.h"
29
30 QTextureViewer::QTextureViewer(QWidget *parent) :
31    QWidget(parent),
32    m_channelSelection(VOGL_CSO_RGBA),
33    m_zoomFactor(1),
34    m_bInvert(false),
35    m_pKtxTexture(NULL),
36    m_baseMipLevel(0),
37    m_maxMipLevel(0)
38 {
39    m_background = QBrush(QColor(0, 0, 0));
40    m_outlinePen = QPen(Qt::black);
41    m_outlinePen.setWidth(1);
42 }
43
44 void QTextureViewer::setTexture(const vogl::ktx_texture* pTexture, uint baseMipLevel, uint maxMipLevel)
45 {
46     m_mipmappedTexture.clear();
47     bool bStatus = m_mipmappedTexture.read_ktx(*pTexture);
48     VOGL_ASSERT(bStatus);
49     if (bStatus)
50     {
51         bStatus = m_mipmappedTexture.convert(vogl::PIXEL_FMT_A8R8G8B8, false, vogl::dxt_image::pack_params());
52
53         m_mipmappedTexture.unflip(true, true);
54
55         VOGL_ASSERT(bStatus);
56     }
57
58     if (!bStatus)
59     {
60         return;
61     }
62
63     delete_pixmaps();
64     m_draw_enabled = true;
65     m_pKtxTexture = pTexture;
66     m_baseMipLevel = baseMipLevel;
67     m_maxMipLevel = maxMipLevel;
68 }
69
70 void QTextureViewer::paintEvent(QPaintEvent *event)
71 {
72     QPainter painter;
73     painter.begin(this);
74
75     if (m_draw_enabled == false)
76     {
77        // clear the viewer
78        painter.fillRect(event->rect(), QWidget::palette().color(QWidget::backgroundRole()));
79     }
80     else
81     {
82        paint(&painter, event);
83     }
84     painter.end();
85 }
86
87 void QTextureViewer::paint(QPainter *painter, QPaintEvent *event)
88 {
89     VOGL_NOTE_UNUSED(event);
90     if (m_pKtxTexture == NULL)
91     {
92         return;
93     }
94
95     if (!m_mipmappedTexture.is_valid() || !m_mipmappedTexture.get_num_levels())
96     {
97         return;
98     }
99
100     painter->save();
101
102     const uint border = 25;
103     const uint minDimension = 10;
104     uint texWidth = m_pKtxTexture->get_width();
105     uint texHeight = m_pKtxTexture->get_height();
106
107     uint drawWidth = vogl::math::maximum<uint>(minDimension, texWidth);
108     uint drawHeight = vogl::math::maximum<uint>(minDimension, texHeight);
109
110     // offset by 1 so that there is room to draw a border around the biggest mip level
111     painter->translate(1, 1);
112
113     // apply zoom factor using scaling
114     painter->scale(m_zoomFactor, m_zoomFactor);
115
116     painter->setPen(m_outlinePen);
117
118     uint numMips = m_pKtxTexture->get_num_mips();
119     uint maxMip = vogl::math::minimum(numMips, m_maxMipLevel);
120     maxMip = vogl::math::minimum(maxMip, m_mipmappedTexture.get_num_levels() - 1);
121
122     uint minimumWidth = 0;
123
124     uint mipWidth = 0;
125     uint mipHeight = 0;
126     uint mipDepth = 0;
127     drawWidth = drawWidth >> m_baseMipLevel;
128     drawHeight = drawHeight >> m_baseMipLevel;
129
130     for (uint mip = m_baseMipLevel; mip <= maxMip; mip++)
131     {
132         if (m_pixmaps.contains(mip) == false && m_mipmappedTexture.is_valid())
133         {
134             QWidget* pParent = (QWidget*)this->parent();
135             QCursor origCursor = pParent->cursor();
136             pParent->setCursor(Qt::WaitCursor);
137
138             vogl::mip_level* mipLevel = m_mipmappedTexture.get_level(0, mip);
139             vogl::image_u8* image = mipLevel->get_image();
140             vogl::color_quad_u8* pPixels = image->get_pixels();
141
142             mipWidth = image->get_width();
143             mipHeight = image->get_height();
144             mipDepth = 1;
145             unsigned char tmp = 0;
146             unsigned int pixelsSize = image->get_total_pixels();
147              vogl::color_quad_u8* pTmpPixels = new vogl::color_quad_u8[pixelsSize];
148             memcpy(pTmpPixels, pPixels, pixelsSize*sizeof(vogl::color_quad_u8));
149             for (uint i = 0; i < pixelsSize; i++)
150             {
151                 adjustChannels(m_channelSelection, pTmpPixels[i].r, pTmpPixels[i].g, pTmpPixels[i].b, pTmpPixels[i].a);
152                 tmp = pTmpPixels[i].r;
153                 pTmpPixels[i].r = pTmpPixels[i].b;
154                 pTmpPixels[i].b = tmp;
155             }
156
157             m_pixmaps.insert(mip, QPixmap::fromImage(QImage((unsigned char*)pTmpPixels, mipWidth, mipHeight, QImage::Format_ARGB32_Premultiplied)));
158             m_pixmapData.insert(mip, pTmpPixels);
159             pParent->setCursor(origCursor);
160         }
161
162         // make sure the rect is 1 pixel around the texture
163         painter->drawRect(-1, -1, drawWidth+1, drawHeight+1);
164
165         if (m_pixmaps.contains(mip))
166         {
167             uint left = 0;
168             uint top = 0;
169             if (m_bInvert)
170             {
171                 // invert
172                 painter->scale(1,-1);
173                 top = -drawHeight;
174             }
175
176             painter->drawPixmap(left, top, drawWidth, drawHeight, m_pixmaps[mip]);
177
178             if (m_bInvert)
179             {
180                 // restore inversion
181                 painter->scale(1,-1);
182             }
183         }
184         painter->translate(drawWidth + border, drawHeight / 2);
185
186         minimumWidth += drawWidth + border;
187
188         drawWidth /= 2;
189         drawHeight /= 2;
190     }
191
192     this->setMinimumSize(minimumWidth * m_zoomFactor, texHeight * m_zoomFactor);
193
194     painter->restore();
195 }
196
197 void QTextureViewer::adjustChannels(ChannelSelectionOption selection, unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a)
198 {
199     switch(selection)
200     {
201     case VOGL_CSO_RGBA:
202     {
203         // premultiply alpha, then force it to 255
204         float blendFactor = a/255.0;
205         r = r*blendFactor + (m_background.color().red()*(1.0-blendFactor));
206         g = g*blendFactor + (m_background.color().green()*(1.0-blendFactor));
207         b = b*blendFactor + (m_background.color().blue()*(1.0-blendFactor));
208         a = 255;
209         break;
210     }
211     case VOGL_CSO_RGB:
212     {
213         // leave rgb, but force a to 255
214         a = 255;
215         break;
216     }
217     case VOGL_CSO_R:
218     {
219         // leave r, and force gb to r so that it appears in greyscale
220         g = r;
221         b = r;
222         a = 255;
223         break;
224     }
225     case VOGL_CSO_G:
226     {
227         // leave g, and force ab to g so that it appears in greyscale
228         r = g;
229         b = g;
230         a = 255;
231         break;
232     }
233     case VOGL_CSO_B:
234     {
235         // leave b, and force ag to b so that it appears in greyscale
236         r = b;
237         g = b;
238         a = 255;
239         break;
240     }
241     case VOGL_CSO_A:
242     {
243         // broadcast a to rgb and then force a to 255
244         r = a;
245         g = a;
246         b = a;
247         a = 255;
248         break;
249     }
250     case VOGL_CSO_ONE_MINUS_RGBA:
251     {
252         r = 255 - r;
253         g = 255 - g;
254         b = 255 - b;
255         a = 255 - a;
256         adjustChannels(VOGL_CSO_RGBA, r, g, b, a);
257         break;
258     }
259     case VOGL_CSO_ONE_MINUS_RGB:
260     {
261         r = 255 - r;
262         g = 255 - g;
263         b = 255 - b;
264         a = 255 - a;
265         adjustChannels(VOGL_CSO_RGB, r, g, b, a);
266         break;
267     }
268     case VOGL_CSO_ONE_MINUS_R:
269     {
270         r = 255 - r;
271         adjustChannels(VOGL_CSO_R, r, g, b, a);
272         break;
273     }
274     case VOGL_CSO_ONE_MINUS_G:
275     {
276         g = 255 - g;
277         adjustChannels(VOGL_CSO_G, r, g, b, a);
278         break;
279     }
280     case VOGL_CSO_ONE_MINUS_B:
281     {
282         b = 255 - b;
283         adjustChannels(VOGL_CSO_B, r, g, b, a);
284         break;
285     }
286     case VOGL_CSO_ONE_MINUS_A:
287     {
288         a = 255 - a;
289         adjustChannels(VOGL_CSO_A, r, g, b, a);
290         break;
291     }
292     case VOGL_CSO_ONE_OVER_RGBA:
293     {
294         r = (r == 0)? 255 : (255 / r);
295         g = (g == 0)? 255 : (255 / g);
296         b = (b == 0)? 255 : (255 / b);
297         a = (a == 0)? 255 : (255 / a);
298         adjustChannels(VOGL_CSO_RGBA, r, g, b, a);
299         break;
300     }
301     case VOGL_CSO_ONE_OVER_RGB:
302     {
303         r = (r == 0)? 255 : (255 / r);
304         g = (g == 0)? 255 : (255 / g);
305         b = (b == 0)? 255 : (255 / b);
306         adjustChannels(VOGL_CSO_RGB, r, g, b, a);
307         break;
308     }
309     case VOGL_CSO_ONE_OVER_R:
310     {
311         r = (r == 0)? 255 : (255 / r);
312         adjustChannels(VOGL_CSO_R, r, g, b, a);
313         break;
314     }
315     case VOGL_CSO_ONE_OVER_G:
316     {
317         g = (g == 0)? 255 : (255 / g);
318         adjustChannels(VOGL_CSO_G, r, g, b, a);
319         break;
320     }
321     case VOGL_CSO_ONE_OVER_B:
322     {
323         b = (b == 0)? 255 : (255 / b);
324         adjustChannels(VOGL_CSO_B, r, g, b, a);
325         break;
326     }
327     case VOGL_CSO_ONE_OVER_A:
328     {
329         a = (a == 0)? 255 : (255 / a);
330         adjustChannels(VOGL_CSO_A, r, g, b, a);
331         break;
332     }
333     }
334 }