C

Qt Quick Ultralite painteditem Example

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "oscPaintedItem.h"

#include <cstring>
#include <memory>
#include <cassert>

#include <platforminterface/drawingengine.h>
#include <qul/painteditemdelegate.h>

const double FACTOR_DEGREE_TO_RAD = 0.0174533;

static uint16_t convertRgb32To16(uint32_t c)
{
    return (((c) >> 3) & 0x001f) | (((c) >> 5) & 0x07e0) | (((c) >> 8) & 0xf800);
}

void pixelBlend(Qul::PlatformInterface::DrawingDevice *device,
                const Qul::PlatformInterface::Rect &clip,
                int x,
                int y,
                Qul::PlatformInterface::Rgba32 color)
{
    assert(device->bitsPerPixel() % 8 == 0);

    if (!clip.contains(x, y)) {
        return;
    }

    uchar *d = device->bits() + (x * device->bitsPerPixel() >> 3) + y * device->bytesPerLine();

    if (16 == device->bitsPerPixel()) {
        uint16_t valRgb565;
        valRgb565 = convertRgb32To16(color.value);

        d[1] = (uint8_t) ((valRgb565 & 0xff00) >> 8);
        d[0] = (uint8_t) (valRgb565 & 0x00ff);
    } else {
        //Written for ARM. For different architecture, endianess has to be taken into considered.
        d[2] = (uint8_t) color.red();
        d[1] = (uint8_t) color.green();
        d[0] = (uint8_t) color.blue();
    }
}

void OscillatorPaintedItem::paintCurvePath(Qul::PlatformInterface::DrawingDevice *device,
                                           const Qul::PlatformInterface::Rect &clip,
                                           const Qul::PlatformInterface::Transform &transform,
                                           Qul::PlatformInterface::Point focus,
                                           int radius,
                                           uint16_t startAngle,
                                           uint16_t endAngle,
                                           Qul::PlatformInterface::Rgba32 color) const
{
    uint16_t angleInDegress = 0;

    for (angleInDegress = startAngle; angleInDegress <= endAngle; angleInDegress++) {
        Qul::PlatformInterface::PointF pos;
        pos.setX(radius * std::cos(FACTOR_DEGREE_TO_RAD * angleInDegress) + focus.x());
        pos.setY(radius * std::sin(FACTOR_DEGREE_TO_RAD * angleInDegress) + focus.y());
        const Qul::PlatformInterface::Point rounded = transform.map(pos).toPoint();
        pixelBlend(device, clip, rounded.x(), rounded.y(), color);
    }
}

void OscillatorPaintedItem::paintBlob(Qul::PlatformInterface::DrawingDevice *device,
                                      const Qul::PlatformInterface::Rect &clip,
                                      Qul::PlatformInterface::Point center,
                                      int radius,
                                      Qul::PlatformInterface::Rgba32 color) const
{
    int angleInDegress = 0;
    Qul::PlatformInterface::Point pos;

    for (angleInDegress = 0; angleInDegress < 360; angleInDegress++) {
        pos.setX(static_cast<int>(radius * std::cos(FACTOR_DEGREE_TO_RAD * angleInDegress) + center.x()));
        pos.setY(static_cast<int>(radius * std::sin(FACTOR_DEGREE_TO_RAD * angleInDegress) + center.y()));
        pixelBlend(device, clip, pos.x(), pos.y(), color);
    }
}

Qul::PlatformInterface::Rect OscillatorPaintedItem::boundingRect(Qul::PlatformInterface::Size size) const
{
    return Qul::PlatformInterface::Rect(0, 0, size.width(), size.height());
}

void OscillatorPaintedItem::paint(Qul::PlatformInterface::DrawingDevice *device,
                                  const Qul::PlatformInterface::Rect &clip,
                                  const Qul::PlatformInterface::Transform &transform,
                                  Qul::PlatformInterface::Size size,
                                  float opacity) const
{
    QUL_UNUSED(opacity);

    static Qul::PlatformInterface::Rgba32 color(static_cast<uint32_t>(0),
                                                static_cast<uint32_t>(0),
                                                static_cast<uint32_t>(0),
                                                static_cast<uint32_t>(255));

    /* Focus of the circular arc is at the center of the bounding rectangle of the painted item */
    Qul::PlatformInterface::PointF focus(size.width() / 2, size.height() / 2);
    device->drawingEngine()->synchronizeForCpuAccess(device, clip);

    /*Paint the curve with its center at middle of the screen
    with arc ranging from 30 to 150 degrees*/
    uint16_t curveRadius = (size.width() / 2) - 10;
    color.setRed(0);
    color.setGreen(0);
    color.setBlue(9);
    paintCurvePath(device, clip, transform, focus.toPoint(), curveRadius, 30, 150, color);

    /* Paint the blob of radius 20.
       Blob center is offset to 20 (equal to radius) to appear above the curve */
    uint16_t blobRadius = 20;

    Qul::PlatformInterface::PointF blobCenter;
    blobCenter.setX((curveRadius - blobRadius) * ::cosf(FACTOR_DEGREE_TO_RAD * angle.value()) + focus.x());
    blobCenter.setY((curveRadius - blobRadius) * ::sinf(FACTOR_DEGREE_TO_RAD * angle.value()) + focus.y());

    blobCenter = transform.map(blobCenter);

    color.setRed(0);
    color.setGreen(0);
    color.setBlue(255);

    paintBlob(device, clip, blobCenter.toPoint(), blobRadius, color);
}