C
Qt Quick Ultralite tvii_effects Example
/****************************************************************************** ** ** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Ultralite module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ******************************************************************************/#include "gaussianblur.h" #include <qul/image.h> #include <platform/platform.h> #include <qul/private/texture.h> #include <qul/private/rasterbuffer.h> #include <platforminterface/log.h> #include <cstring> #include <memory> #ifdef QUL_TVIIC_PLATFORM #include <sm_util.h> #include <pe_matrix.h> #include <ut_filter.h> #include "cygfx.h" #else #include <QGraphicsBlurEffect> #include <QImage> #include <QPainter> #include <QLabel> #include <QVector> #include "desktop.h" #endif #include <qul/private/unicodestring.h> #include <qul/private/image_p.h> Qul::PlatformInterface::Rect GaussianBlurDelegate::boundingRect(Qul::PlatformInterface::Size) const { int padding = int(ceil(blurValue())); if (source.value().textureCount() != 1) { Qul::PlatformInterface::log("TVII effects: gaussian blur: Unexpected texture count %i\r\n", source.value().textureCount()); std::terminate(); } auto texture = source.value().texture(); return Qul::PlatformInterface::Rect(-padding, -padding, texture.width() + 2 * padding, texture.height() + 2 * padding); } #ifndef QUL_TVIIC_PLATFORM QImage blurred(const QImage &source, int padding, float sigma) { if (sigma <= 0) return source; QLabel label; label.setPixmap(QPixmap::fromImage(source)); label.resize(source.size()); QGraphicsBlurEffect *effect = new QGraphicsBlurEffect; // approximate the same blurriness as on Traveo II effect->setBlurRadius(sigma * 2 + 1); effect->setBlurHints(QGraphicsBlurEffect::QualityHint); label.setGraphicsEffect(effect); QImage image(source.width() + 2 * padding, source.height() + 2 * padding, QImage::Format_ARGB32_Premultiplied); image.fill(0x0); QWidget widget; widget.resize(image.size()); label.setParent(&widget); label.move(padding, padding); widget.render(&image, QPoint(), QRegion(), QWidget::DrawChildren); label.setParent(nullptr); return image; } #endif void GaussianBlurDelegate::blurChanged() { m_blurDirty = true; update(); } void GaussianBlurDelegate::paint(Qul::PlatformInterface::DrawingDevice *device, const Qul::PlatformInterface::Rect &clip, const Qul::PlatformInterface::Transform &transform, Qul::PlatformInterface::Size, float opacity) const { float sigma = blurValue(); // Values near 1.64f trigger a bug in the TRAVEO™ T2G Graphics Driver // (versions 1.2.1 and 2e.2.0) where the image doesn't get shown at all. As // a workaround, round the values to the second decimal place, and skip the // value that triggers the bug. int sigmaPercent = int(sigma * 100); if (sigmaPercent == 164) ++sigmaPercent; sigma = sigmaPercent * 0.01f; auto texture = source.value().texture(); if (!m_initialized) { #ifdef QUL_TVIIC_PLATFORM CyGfx::loadSurface(&m_source, texture); #endif m_initialized = true; } int padding = int(ceil(sigma)); const Qul::PlatformInterface::Transform adjusted = Qul::PlatformInterface::Transform::fromTranslation(-padding, -padding) * transform; #ifdef QUL_TVIIC_PLATFORM void **platformContext = static_cast<void **>(device->platformContext()); CYGFX_BE_CONTEXT ctx = static_cast<CYGFX_BE_CONTEXT>(platformContext[0]); CYGFX_BE_CONTEXT drawCtx = static_cast<CYGFX_BE_CONTEXT>(platformContext[2]); CYGFX_ERROR ret = CYGFX_OK; if (m_blurDirty && sigma > 0) { m_index = (m_index + 1) % 3; auto &surface = m_blurred[m_index]; surface.Delete(); surface.CreateBuffer(texture.width() + padding, texture.height() + padding); UTIL_SUCCESS(ret, CyGfx_BeBindSurface(drawCtx, CYGFX_BE_TARGET_STORE | CYGFX_BE_TARGET_DST, surface)); UTIL_SUCCESS(ret, CyGfx_BeBindSurface(drawCtx, CYGFX_BE_TARGET_SRC, m_source)); utFilterSetGaussFilter(drawCtx, CYGFX_CM_FILTER_CHANNEL_RGBA, sigma); UTIL_SUCCESS(ret, CyGfx_BeBlt(drawCtx, padding, padding)); UTIL_SUCCESS(ret, CyGfx_BeFinish(drawCtx)); utFilterFree(drawCtx); m_blurDirty = false; } Mat3x3 matrix{adjusted.m11(), adjusted.m12(), adjusted.m13(), adjusted.m21(), adjusted.m22(), adjusted.m23(), adjusted.dx(), adjusted.dy(), adjusted.m33()}; bool hasClipping = false; if (clip != Qul::PlatformInterface::Rect(0, 0, device->width(), device->height())) { // Blend only in clip area UTIL_SUCCESS(ret, CyGfx_BeSetSurfAttribute(ctx, CYGFX_BE_TARGET_STORE, CYGFX_BE_SURF_ATTR_USE_CLIPPING, CYGFX_TRUE)); UTIL_SUCCESS(ret, CyGfx_BeActiveArea(ctx, CYGFX_BE_TARGET_STORE, clip.x(), clip.y(), clip.width(), clip.height())); } UTIL_SUCCESS(ret, CyGfx_BeBindSurface(ctx, CYGFX_BE_TARGET_SRC, sigma > 0 ? m_blurred[m_index] : m_source)); if (opacity != 1) { UTIL_SUCCESS(ret, CyGfx_BeSetSurfAttribute(ctx, CYGFX_BE_TARGET_SRC, CYGFX_BE_SURF_ATTR_COLOR, CYGFX_SM_COLOR_TO_RGBA(255, 255, 255, int(255 * opacity)))); UTIL_SUCCESS(ret, CyGfx_BeSetSurfAttribute(ctx, CYGFX_BE_TARGET_SRC, CYGFX_BE_SURF_ATTR_ALPHAMULTI, CYGFX_TRUE)); } UTIL_SUCCESS(ret, CyGfx_BeSetGeoMatrix(ctx, CYGFX_BE_TARGET_SRC, CYGFX_BE_GEO_MATRIX_FORMAT_3X3, matrix)); UTIL_SUCCESS(ret, CyGfx_BeBlt(ctx, 0, 0)); UTIL_SUCCESS(ret, CyGfx_BeBindSurface(ctx, CYGFX_BE_TARGET_MASK, nullptr)); if (hasClipping) UTIL_SUCCESS(ret, CyGfx_BeSetSurfAttribute(ctx, CYGFX_BE_TARGET_STORE, CYGFX_BE_SURF_ATTR_USE_CLIPPING, CYGFX_FALSE)); #else QPainter *p = static_cast<QPainter *>(device->platformContext()); QImage image(texture.data(), texture.width(), texture.height(), texture.bytesPerLine(), toQImageFormat(texture.format())); QImage blurredImage = blurred(image, padding, sigma); p->save(); p->setClipRect(QRect(clip.x(), clip.y(), clip.width(), clip.height())); p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); p->setTransform(toQTransform(adjusted)); p->setOpacity(opacity); p->drawImage(QPoint(), blurredImage); p->restore(); #endif }