2017-07-21 16:21:34 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskGraphicTextureFactory.h"
|
|
|
|
|
2018-07-19 12:10:48 +00:00
|
|
|
#include <qopenglcontext.h>
|
|
|
|
#include <qopenglframebufferobject.h>
|
|
|
|
#include <qopenglfunctions.h>
|
2018-09-30 16:09:17 +00:00
|
|
|
#include <qopenglextrafunctions.h>
|
2018-08-03 06:15:28 +00:00
|
|
|
#include <qopenglpaintdevice.h>
|
2018-07-19 12:10:48 +00:00
|
|
|
#include <qopengltexture.h>
|
2017-07-21 16:21:34 +00:00
|
|
|
|
2018-07-19 12:10:48 +00:00
|
|
|
#include <qpainter.h>
|
|
|
|
#include <qquickwindow.h>
|
2017-07-21 16:21:34 +00:00
|
|
|
|
|
|
|
static uint qskTextureFBO(
|
|
|
|
const QRect& rect, Qt::AspectRatioMode scalingMode,
|
|
|
|
const QskGraphic& graphic, const QskColorFilter& filter )
|
|
|
|
{
|
|
|
|
QOpenGLFramebufferObjectFormat format1;
|
|
|
|
format1.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil );
|
|
|
|
// ### TODO: get samples from window instead
|
|
|
|
format1.setSamples( QOpenGLContext::currentContext()->format().samples() );
|
|
|
|
|
2018-07-13 13:09:25 +00:00
|
|
|
const QRect sourceRect( QPoint(), rect.size() );
|
2017-07-21 16:21:34 +00:00
|
|
|
|
|
|
|
QOpenGLFramebufferObject multisampledFbo( sourceRect.size(), format1 );
|
|
|
|
|
|
|
|
QOpenGLPaintDevice pd( sourceRect.size() );
|
|
|
|
|
|
|
|
QPainter painter( &pd );
|
|
|
|
|
2018-07-13 13:09:25 +00:00
|
|
|
graphic.render( &painter, sourceRect, filter, scalingMode );
|
2017-07-21 16:21:34 +00:00
|
|
|
|
|
|
|
#if 1
|
|
|
|
if ( format1.samples() > 0 )
|
|
|
|
{
|
|
|
|
// multisampling in the window surface might get lost
|
|
|
|
// as a side effect of rendering to the FBO.
|
|
|
|
// weired, needs to be investigated more
|
|
|
|
painter.setRenderHint( QPainter::Antialiasing, true );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
painter.end();
|
|
|
|
|
|
|
|
QOpenGLFramebufferObjectFormat format2;
|
|
|
|
format2.setAttachment( QOpenGLFramebufferObject::NoAttachment );
|
|
|
|
|
|
|
|
QOpenGLFramebufferObject fbo( sourceRect.size(), format2 );
|
|
|
|
|
|
|
|
// mirror vertically to be compliant with what QQuickTextureFactory expects.
|
|
|
|
// for some reason we have to add 1 pixel to avoid that the mirrored
|
|
|
|
// image gets cut off.
|
|
|
|
|
|
|
|
const QRect targetRect( sourceRect.x(), sourceRect.bottom() + 1,
|
|
|
|
sourceRect.width(), -sourceRect.height() );
|
|
|
|
|
2018-08-03 06:15:28 +00:00
|
|
|
QOpenGLFramebufferObject::blitFramebuffer(
|
|
|
|
&fbo, sourceRect, &multisampledFbo, targetRect );
|
2017-07-21 16:21:34 +00:00
|
|
|
|
|
|
|
return fbo.takeTexture();
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint qskTextureRaster(
|
|
|
|
const QRect& rect, Qt::AspectRatioMode scalingMode,
|
|
|
|
const QskGraphic& graphic, const QskColorFilter& filter )
|
|
|
|
{
|
2018-07-13 13:09:25 +00:00
|
|
|
QImage image( rect.size(), QImage::Format_RGBA8888_Premultiplied );
|
2017-07-21 16:21:34 +00:00
|
|
|
image.fill( Qt::transparent );
|
2018-07-13 13:09:25 +00:00
|
|
|
|
2017-07-21 16:21:34 +00:00
|
|
|
{
|
|
|
|
QPainter painter( &image );
|
|
|
|
graphic.render( &painter, rect, filter, scalingMode );
|
|
|
|
}
|
|
|
|
|
2018-09-30 16:09:17 +00:00
|
|
|
const auto target = QOpenGLTexture::Target2D;
|
|
|
|
|
|
|
|
auto context = QOpenGLContext::currentContext();
|
|
|
|
if ( context == nullptr )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
auto& f = *context->functions();
|
|
|
|
|
|
|
|
GLint oldTexture; // we can't rely on having OpenGL Direct State Access
|
|
|
|
f.glGetIntegerv( QOpenGLTexture::BindingTarget2D, &oldTexture );
|
|
|
|
|
|
|
|
GLuint textureId;
|
|
|
|
f.glGenTextures( 1, &textureId );
|
|
|
|
|
|
|
|
f.glBindTexture( target, textureId );
|
|
|
|
|
|
|
|
f.glTexParameteri( target, GL_TEXTURE_MIN_FILTER, QOpenGLTexture::Nearest );
|
|
|
|
f.glTexParameteri( target, GL_TEXTURE_MAG_FILTER, QOpenGLTexture::Nearest );
|
|
|
|
|
|
|
|
f.glTexParameteri( target, GL_TEXTURE_WRAP_S, QOpenGLTexture::ClampToEdge );
|
|
|
|
f.glTexParameteri( target, GL_TEXTURE_WRAP_T, QOpenGLTexture::ClampToEdge );
|
|
|
|
|
|
|
|
if ( QOpenGLTexture::hasFeature( QOpenGLTexture::ImmutableStorage ) )
|
|
|
|
{
|
|
|
|
auto& ef = *context->extraFunctions();
|
|
|
|
ef.glTexStorage2D( target, 1,
|
|
|
|
QOpenGLTexture::RGBA8_UNorm, image.width(), image.height() );
|
|
|
|
|
|
|
|
f.glTexSubImage2D( target, 0, 0, 0, image.width(), image.height(),
|
|
|
|
QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
f.glTexImage2D( target, 0, QOpenGLTexture::RGBA8_UNorm,
|
|
|
|
image.width(), image.height(), 0,
|
|
|
|
QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() );
|
|
|
|
}
|
|
|
|
|
|
|
|
f.glBindTexture( target, oldTexture );
|
|
|
|
|
2017-07-21 16:21:34 +00:00
|
|
|
return textureId;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskGraphicTextureFactory::QskGraphicTextureFactory()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskGraphicTextureFactory::QskGraphicTextureFactory(
|
2018-08-03 06:15:28 +00:00
|
|
|
const QskGraphic& graphic, const QSize& size )
|
|
|
|
: m_graphic( graphic )
|
|
|
|
, m_size( size )
|
2017-07-21 16:21:34 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskGraphicTextureFactory::~QskGraphicTextureFactory()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QSGTexture* QskGraphicTextureFactory::createTexture( QQuickWindow* window ) const
|
|
|
|
{
|
|
|
|
const QRect textureRect( 0, 0, m_size.width(), m_size.height() );
|
|
|
|
|
|
|
|
const uint textureId = createTexture( QskGraphicTextureFactory::OpenGL,
|
|
|
|
textureRect, Qt::KeepAspectRatio, m_graphic, m_colorFilter );
|
|
|
|
|
|
|
|
const auto flags = static_cast< QQuickWindow::CreateTextureOptions >(
|
|
|
|
QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture );
|
|
|
|
|
|
|
|
return window->createTextureFromId( textureId, m_size, flags );
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize QskGraphicTextureFactory::textureSize() const
|
|
|
|
{
|
|
|
|
return m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int QskGraphicTextureFactory::textureByteCount() const
|
|
|
|
{
|
|
|
|
return m_size.width() * m_size.height() * 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
QImage QskGraphicTextureFactory::image() const
|
|
|
|
{
|
|
|
|
return m_graphic.toImage( m_size, Qt::KeepAspectRatio );
|
|
|
|
}
|
|
|
|
|
2018-07-13 13:09:25 +00:00
|
|
|
// ### TODO: get the FBO samples from the window
|
2017-07-21 16:21:34 +00:00
|
|
|
uint QskGraphicTextureFactory::createTexture(
|
|
|
|
RenderMode mode, const QRect& rect, Qt::AspectRatioMode scalingMode,
|
|
|
|
const QskGraphic& graphic, const QskColorFilter& filter )
|
|
|
|
{
|
|
|
|
if ( mode == QskGraphicTextureFactory::Raster )
|
|
|
|
return qskTextureRaster( rect, scalingMode, graphic, filter );
|
|
|
|
else
|
|
|
|
return qskTextureFBO( rect, scalingMode, graphic, filter );
|
|
|
|
}
|