C

Qt Quick Ultralite traveo_t2g_effects Example

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "imagewithopacitymask.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 "cygfx.h"
#else
#include <QImage>
#include <QPainter>
#include <QVector>
#include "desktop.h"
#endif

#include <qul/private/unicodestring.h>
#include <qul/private/image_p.h>

#include <platforminterface/log.h>

Qul::PlatformInterface::Rect ImageWithOpacityMaskDelegate::boundingRect(Qul::PlatformInterface::Size) const
{
    if (source.value().textureCount() != 1) {
        Qul::PlatformInterface::log("TVII effects: image with opacity mask: Unexpected texture count %i\r\n",
                                    source.value().textureCount());
        std::terminate();
    }

    auto texture = source.value().texture();

    return Qul::PlatformInterface::Rect(0, 0, texture.width(), texture.height());
}

void ImageWithOpacityMaskDelegate::paint(Qul::PlatformInterface::DrawingDevice *device,
                                         const Qul::PlatformInterface::Rect &clip,
                                         const Qul::PlatformInterface::Transform &transform,
                                         Qul::PlatformInterface::Size,
                                         float opacity) const
{
    if (source.value().textureCount() != 1) {
        Qul::PlatformInterface::log("TVII effects: image with opacity mask: Unexpected texture count %i\r\n",
                                    source.value().textureCount());
        std::terminate();
    }

    auto texture = source.value().texture();

    if (mask.value().textureCount() != 1) {
        Qul::PlatformInterface::log("TVII effects: image with opacity mask: Unexpected texture count %i\r\n",
                                    mask.value().textureCount());
        std::terminate();
    }

    auto maskTexture = mask.value().texture();

    if (!m_initialized) {
#ifdef QUL_TVIIC_PLATFORM
        CyGfx::loadSurface(&m_source, texture);
        CyGfx::loadSurface(&m_mask, maskTexture);
#endif
        m_initialized = true;
    }

#ifdef QUL_TVIIC_PLATFORM
    void **platformContext = static_cast<void **>(device->platformContext());
    CYGFX_BE_CONTEXT ctx = static_cast<CYGFX_BE_CONTEXT>(platformContext[0]);
    CYGFX_SURFACE surface = static_cast<CYGFX_SURFACE>(platformContext[1]);

    CYGFX_ERROR ret = CYGFX_OK;
    CYGFX_U32 renderMode;
    UTIL_SUCCESS(ret, CyGfx_BeGetAttribute(ctx, CYGFX_BE_CTX_ATTR_RENDER_MODE, &renderMode));
    if (renderMode == CYGFX_BE_RENDER_MODE_IBO) {
        Qul::PlatformInterface::log("ImageWithOpacityMaskDelegate doesn't support IBO layers\n");
        return;
    }

    Mat3x3 matrix{transform.m11(),
                  transform.m12(),
                  transform.m13(),
                  transform.m21(),
                  transform.m22(),
                  transform.m23(),
                  transform.dx(),
                  transform.dy(),
                  transform.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()));
    }

    CYGFX_SURFACE transformedMask = CYGFX_BE_SURF_MASK_ALPHA;

    UTIL_SUCCESS(ret, CyGfx_BeBindSurface(ctx, CYGFX_BE_TARGET_SRC, m_mask));
    UTIL_SUCCESS(ret, CyGfx_BeBindSurface(ctx, CYGFX_BE_TARGET_STORE, transformedMask));
    UTIL_SUCCESS(ret, CyGfx_BeBindSurface(ctx, CYGFX_BE_TARGET_DST, 0));
    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_STORE | CYGFX_BE_TARGET_DST, surface));

    UTIL_SUCCESS(ret, CyGfx_BeBindSurface(ctx, CYGFX_BE_TARGET_SRC, m_source));
    if (!Qul::Private::qFuzzyCompare(opacity, 1.0f)) {
        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_BeBindSurface(ctx, CYGFX_BE_TARGET_MASK, transformedMask));
    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 maskImage(maskTexture.data(),
                     maskTexture.width(),
                     maskTexture.height(),
                     maskTexture.bytesPerLine(),
                     toQImageFormat(maskTexture.format()));

    QImage withMask = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
    QPainter imagePainter(&withMask);
    imagePainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    imagePainter.drawImage(0, 0, maskImage);
    imagePainter.end();

    p->save();
    p->setClipRect(QRect(clip.x(), clip.y(), clip.width(), clip.height()));
    p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    p->setTransform(toQTransform(transform));
    p->setOpacity(opacity);
    p->drawImage(QPoint(), withMask);
    p->restore();
#endif
}