1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 **************************************************************************/
27 #include "vogleditor_qtextureviewer.h"
28 #include "vogl_buffer_stream.h"
30 QTextureViewer::QTextureViewer(QWidget *parent) :
32 m_channelSelection(VOGL_CSO_RGBA),
39 m_background = QBrush(QColor(0, 0, 0));
40 m_outlinePen = QPen(Qt::black);
41 m_outlinePen.setWidth(1);
44 void QTextureViewer::setTexture(const vogl::ktx_texture* pTexture, uint baseMipLevel, uint maxMipLevel)
46 m_mipmappedTexture.clear();
47 bool bStatus = m_mipmappedTexture.read_ktx(*pTexture);
51 bStatus = m_mipmappedTexture.convert(vogl::PIXEL_FMT_A8R8G8B8, false, vogl::dxt_image::pack_params());
53 m_mipmappedTexture.unflip(true, true);
64 m_draw_enabled = true;
65 m_pKtxTexture = pTexture;
66 m_baseMipLevel = baseMipLevel;
67 m_maxMipLevel = maxMipLevel;
70 void QTextureViewer::paintEvent(QPaintEvent *event)
75 if (m_draw_enabled == false)
78 painter.fillRect(event->rect(), QWidget::palette().color(QWidget::backgroundRole()));
82 paint(&painter, event);
87 void QTextureViewer::paint(QPainter *painter, QPaintEvent *event)
89 VOGL_NOTE_UNUSED(event);
90 if (m_pKtxTexture == NULL)
95 if (!m_mipmappedTexture.is_valid() || !m_mipmappedTexture.get_num_levels())
102 const uint border = 25;
103 const uint minDimension = 10;
104 uint texWidth = m_pKtxTexture->get_width();
105 uint texHeight = m_pKtxTexture->get_height();
107 uint drawWidth = vogl::math::maximum<uint>(minDimension, texWidth);
108 uint drawHeight = vogl::math::maximum<uint>(minDimension, texHeight);
110 // offset by 1 so that there is room to draw a border around the biggest mip level
111 painter->translate(1, 1);
113 // apply zoom factor using scaling
114 painter->scale(m_zoomFactor, m_zoomFactor);
116 painter->setPen(m_outlinePen);
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);
122 uint minimumWidth = 0;
127 drawWidth = drawWidth >> m_baseMipLevel;
128 drawHeight = drawHeight >> m_baseMipLevel;
130 for (uint mip = m_baseMipLevel; mip <= maxMip; mip++)
132 if (m_pixmaps.contains(mip) == false && m_mipmappedTexture.is_valid())
134 QWidget* pParent = (QWidget*)this->parent();
135 QCursor origCursor = pParent->cursor();
136 pParent->setCursor(Qt::WaitCursor);
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();
142 mipWidth = image->get_width();
143 mipHeight = image->get_height();
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++)
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;
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);
162 // make sure the rect is 1 pixel around the texture
163 painter->drawRect(-1, -1, drawWidth+1, drawHeight+1);
165 if (m_pixmaps.contains(mip))
172 painter->scale(1,-1);
176 painter->drawPixmap(left, top, drawWidth, drawHeight, m_pixmaps[mip]);
181 painter->scale(1,-1);
184 painter->translate(drawWidth + border, drawHeight / 2);
186 minimumWidth += drawWidth + border;
192 this->setMinimumSize(minimumWidth * m_zoomFactor, texHeight * m_zoomFactor);
197 void QTextureViewer::adjustChannels(ChannelSelectionOption selection, unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a)
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));
213 // leave rgb, but force a to 255
219 // leave r, and force gb to r so that it appears in greyscale
227 // leave g, and force ab to g so that it appears in greyscale
235 // leave b, and force ag to b so that it appears in greyscale
243 // broadcast a to rgb and then force a to 255
250 case VOGL_CSO_ONE_MINUS_RGBA:
256 adjustChannels(VOGL_CSO_RGBA, r, g, b, a);
259 case VOGL_CSO_ONE_MINUS_RGB:
265 adjustChannels(VOGL_CSO_RGB, r, g, b, a);
268 case VOGL_CSO_ONE_MINUS_R:
271 adjustChannels(VOGL_CSO_R, r, g, b, a);
274 case VOGL_CSO_ONE_MINUS_G:
277 adjustChannels(VOGL_CSO_G, r, g, b, a);
280 case VOGL_CSO_ONE_MINUS_B:
283 adjustChannels(VOGL_CSO_B, r, g, b, a);
286 case VOGL_CSO_ONE_MINUS_A:
289 adjustChannels(VOGL_CSO_A, r, g, b, a);
292 case VOGL_CSO_ONE_OVER_RGBA:
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);
301 case VOGL_CSO_ONE_OVER_RGB:
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);
309 case VOGL_CSO_ONE_OVER_R:
311 r = (r == 0)? 255 : (255 / r);
312 adjustChannels(VOGL_CSO_R, r, g, b, a);
315 case VOGL_CSO_ONE_OVER_G:
317 g = (g == 0)? 255 : (255 / g);
318 adjustChannels(VOGL_CSO_G, r, g, b, a);
321 case VOGL_CSO_ONE_OVER_B:
323 b = (b == 0)? 255 : (255 / b);
324 adjustChannels(VOGL_CSO_B, r, g, b, a);
327 case VOGL_CSO_ONE_OVER_A:
329 a = (a == 0)? 255 : (255 / a);
330 adjustChannels(VOGL_CSO_A, r, g, b, a);