KisDistanceInformation KisCurvePaintOp::paintLine(const KisPaintInformation& pi1, const KisPaintInformation& pi2, const KisDistanceInformation& savedDist)
{
    Q_UNUSED(savedDist);
    if (!painter()) return KisDistanceInformation();
    m_dev = painter()->device();
    if (!m_dev) return KisDistanceInformation();

    if (!m_dab) {
        m_dab = new KisPaintDevice(painter()->device()->colorSpace());
    } else {
        m_dab->clear();
    }
    //write device, read device, position
    m_curveBrush.paintLine(m_dab, m_dev, pi1, pi2);

    QRect rc = m_dab->extent();

    painter()->bitBlt(rc.topLeft(), m_dab, rc);

    KisVector2D end = toKisVector2D(pi2.pos());
    KisVector2D start = toKisVector2D(pi1.pos());
    KisVector2D dragVec = end - start;
    return KisDistanceInformation(0, dragVec.norm());

}
Example #2
0
void KisToolFreehandHelper::stabilizerPollAndPaint()
{
    KisStabilizedEventsSampler::iterator it;
    KisStabilizedEventsSampler::iterator end;
    std::tie(it, end) = m_d->stabilizedSampler.range();
    QVector<KisPaintInformation> delayedPaintTodoItems;

    for (; it != end; ++it) {
        KisPaintInformation sampledInfo = *it;

        bool canPaint = true;

        if (m_d->smoothingOptions->useDelayDistance()) {
            const qreal R = m_d->smoothingOptions->delayDistance() /
                            m_d->resources->effectiveZoom();

            QPointF diff = sampledInfo.pos() - m_d->previousPaintInformation.pos();
            qreal dx = sqrt(pow2(diff.x()) + pow2(diff.y()));

            canPaint = dx > R;
        }

        if (canPaint) {
            KisPaintInformation newInfo =
                m_d->getStabilizedPaintInfo(m_d->stabilizerDeque, sampledInfo);

            if (m_d->stabilizerDelayedPaintHelper.running()) {
                delayedPaintTodoItems.append(newInfo);
            } else {
                paintLine(m_d->previousPaintInformation, newInfo);
            }
            m_d->previousPaintInformation = newInfo;

            // Push the new entry through the queue
            m_d->stabilizerDeque.dequeue();
            m_d->stabilizerDeque.enqueue(sampledInfo);
        } else if (m_d->stabilizerDeque.head().pos() != m_d->previousPaintInformation.pos()) {

            QQueue<KisPaintInformation>::iterator it = m_d->stabilizerDeque.begin();
            QQueue<KisPaintInformation>::iterator end = m_d->stabilizerDeque.end();

            while (it != end) {
                *it = m_d->previousPaintInformation;
                ++it;
            }
        }
    }

    m_d->stabilizedSampler.clear();

    if (m_d->stabilizerDelayedPaintHelper.running()) {
        m_d->stabilizerDelayedPaintHelper.update(delayedPaintTodoItems);
    } else {
        emit requestExplicitUpdateOutline();
    }
}
Example #3
0
KisSpacingInformation KisLiquifyPaintop::paintAt(const KisPaintInformation &pi)
{
    static const qreal sizeToSigmaCoeff = 1.0 / 3.0;
    const qreal size = sizeToSigmaCoeff *
        (m_d->props.sizeHasPressure() ?
         pi.pressure() * m_d->props.size():
         m_d->props.size());

    const qreal spacing = m_d->props.spacing() * size;

    const qreal reverseCoeff =
        m_d->props.mode() !=
        KisLiquifyProperties::UNDO &&
        m_d->props.reverseDirection() ? -1.0 : 1.0;
    const qreal amount = m_d->props.amountHasPressure() ?
        pi.pressure() * reverseCoeff * m_d->props.amount():
        reverseCoeff * m_d->props.amount();

    const bool useWashMode = m_d->props.useWashMode();
    const qreal flow = m_d->props.flow();

    switch (m_d->props.mode()) {
    case KisLiquifyProperties::MOVE: {
        const qreal offsetLength = size * amount;
        m_d->worker->translatePoints(pi.pos(),
                                     pi.drawingDirectionVector() * offsetLength,
                                     size, useWashMode, flow);

        break;
    }
    case KisLiquifyProperties::SCALE:
        m_d->worker->scalePoints(pi.pos(),
                                 amount,
                                 size, useWashMode, flow);
        break;
    case KisLiquifyProperties::ROTATE:
        m_d->worker->rotatePoints(pi.pos(),
                                  2.0 * M_PI * amount,
                                  size, useWashMode, flow);
        break;
    case KisLiquifyProperties::OFFSET: {
        const qreal offsetLength = size * amount;
        m_d->worker->translatePoints(pi.pos(),
                                     KisAlgebra2D::rightUnitNormal(pi.drawingDirectionVector()) * offsetLength,
                                     size, useWashMode, flow);
        break;
    }
    case KisLiquifyProperties::UNDO:
        m_d->worker->undoPoints(pi.pos(),
                                amount,
                                size);

        break;
    case KisLiquifyProperties::N_MODES:
        qFatal("Not supported mode");
    }

    return KisSpacingInformation(spacing);
}
Example #4
0
void KisToolLineHelper::start(KoPointerEvent *event, KoCanvasResourceManager *resourceManager)
{
    if (!m_d->enabled) return;

    KisPaintInformation pi =
            m_d->infoBuilder->startStroke(event, elapsedStrokeTime(), resourceManager);

    if (!m_d->useSensors) {
        pi = KisPaintInformation(pi.pos());
    }

    m_d->linePoints.append(pi);
}
Example #5
0
void KisBrushOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()->device()) return;

    KisBrushSP brush = m_brush;
    Q_ASSERT(brush);
    if (!brush) return;

    KisPaintInformation adjustedInfo = settings->m_optionsWidget->m_sizeOption->apply(info);
    if (!brush->canPaintFor(adjustedInfo))
        return;

    KisPaintDeviceSP device = painter()->device();

    double pScale = KisPaintOp::scaleForPressure(adjustedInfo.pressure());   // TODO: why is there scale and pScale that seems to contains the same things ?
    QPointF hotSpot = brush->hotSpot(pScale, pScale);
    QPointF pt = info.pos() - hotSpot;

    // Split the coordinates into integer plus fractional parts. The integer
    // is where the dab will be positioned and the fractional part determines
    // the sub-pixel positioning.
    qint32 x;
    double xFraction;
    qint32 y;
    double yFraction;

    splitCoordinate(pt.x(), &x, &xFraction);
    splitCoordinate(pt.y(), &y, &yFraction);

    quint8 origOpacity = settings->m_optionsWidget->m_opacityOption->apply(painter(), info.pressure());
    KoColor origColor = settings->m_optionsWidget->m_darkenOption->apply(painter(), info.pressure());

    double scale = KisPaintOp::scaleForPressure(adjustedInfo.pressure());

    KisFixedPaintDeviceSP dab = cachedDab(device->colorSpace());
    if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
        dab = brush->image(device->colorSpace(), scale, 0.0, adjustedInfo, xFraction, yFraction);
    } else {
        KoColor color = painter()->paintColor();
        color.convertTo(dab->colorSpace());
        brush->mask(dab, color, scale, scale, 0.0, info, xFraction, yFraction);
    }

    painter()->bltFixed(QPoint(x, y), dab, dab->bounds());
    painter()->setOpacity(origOpacity);
    painter()->setPaintColor(origColor);

}
Example #6
0
QPainterPath KisDuplicateOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode)
{
    QPainterPath path;

    // clone tool should always show an outline
    path = KisBrushBasedPaintOpSettings::brushOutlineImpl(info, mode, 1.0, true);

    QPainterPath copy(path);
    QRectF rect2 = copy.boundingRect();
    if (m_isOffsetNotUptodate || !getBool(DUPLICATE_MOVE_SOURCE_POINT)) {
        copy.translate(m_position - info.pos());
    }
    else {
        copy.translate(-m_offset);
    }

    path.addPath(copy);

    qreal dx = rect2.width() / 4.0;
    qreal dy = rect2.height() / 4.0;
    rect2.adjust(dx, dy, -dx, -dy);

    path.moveTo(rect2.topLeft());
    path.lineTo(rect2.bottomRight());

    path.moveTo(rect2.topRight());
    path.lineTo(rect2.bottomLeft());

    return path;
}
KisSpacingInformation KisChalkPaintOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()) return 1.0;

    if (!m_dab) {
        m_dab = source()->createCompositionSourceDevice();
    } else {
        m_dab->clear();
    }

    qreal x1, y1;

    x1 = info.pos().x();
    y1 = info.pos().y();

    quint8 origOpacity = m_opacityOption.apply(painter(), info);
    m_chalkBrush->paint(m_dab, x1, y1, painter()->paintColor());

    QRect rc = m_dab->extent();

    painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height());
    painter()->renderMirrorMask(rc,m_dab);
    painter()->setOpacity(origOpacity);
    return 1.0;
}
QPainterPath KisGridPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const
{
    QPainterPath path;
    if (mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) {
        qreal sizex = getInt(GRID_WIDTH) * getDouble(GRID_SCALE);
        qreal sizey = getInt(GRID_HEIGHT) * getDouble(GRID_SCALE);
        QRectF rc(0, 0, sizex, sizey);
        rc.translate(-rc.center());
        path.addRect(rc);
        
        QPainterPath tiltLine;
        QLineF tiltAngle(QPointF(0.0,0.0), QPointF(0.0,sizex));
        tiltAngle.setLength(qMax(sizex*0.5, 50.0) * (1 - info.tiltElevation(info, 60.0, 60.0, true)));
        tiltAngle.setAngle((360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0))-3.0);
        tiltLine.moveTo(tiltAngle.p1());
        tiltLine.lineTo(tiltAngle.p2());
        tiltAngle.setAngle((360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0))+3.0);
        tiltLine.lineTo(tiltAngle.p2());
        tiltLine.lineTo(tiltAngle.p1());

        path = outlineFetcher()->fetchOutline(info, this, path);
        
        if (mode == CursorTiltOutline) {
            path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, 1.0, 0.0, true, 0, 0));
        }
    }
    return path;
}
Example #9
0
void SprayBrush::paintDistanceMap(KisPaintDeviceSP dev, const KisPaintInformation &info, const KoColor &painterColor){
    KisRandomAccessor accessor = dev->createRandomAccessor(0, 0);
    KoColor color = painterColor;

    qreal posX = info.pos().x();
    qreal posY = info.pos().y();
    
    qreal opacity = 255;
    for (int y = -m_radius; y <= m_radius; y++){
        for (int x = -m_radius; x <= m_radius; x++){
            //opacity = sqrt(y*y + x*x) / m_radius;
            opacity = (y*y + x*x) / (m_radius * m_radius);
            opacity = 1.0 - opacity;
            opacity *= m_scale;

            if (opacity < 0) continue;
            if (opacity > 1.0) opacity = 1.0;

            if ( (y*y + x*x) <= (m_radius * m_radius) )
            {
                color.setOpacity( opacity * 255);
                accessor.moveTo(x + posX, y + posY);
                memcpy( accessor.rawData(), color.data(), dev->colorSpace()->pixelSize() );
            }

        }
    }
}
Example #10
0
void KisCurvePaintOp::paintLine(KisPaintDeviceSP dab, const KisPaintInformation &pi1, const KisPaintInformation &pi2)
{
    if (!m_painter) {
        m_painter = new KisPainter(dab);
        m_painter->setPaintColor(painter()->paintColor());
    }

    int maxPoints = m_curveProperties.curve_stroke_history_size;

    m_points.append(pi2.pos());

    while (m_points.length() > maxPoints) {
        m_points.removeFirst();
    }

    const qreal additionalScale = KisLodTransform::lodToScale(painter()->device());
    const qreal lineWidth = additionalScale * m_lineWidthOption.apply(pi2, m_curveProperties.curve_line_width);

    QPen pen(QBrush(Qt::white), lineWidth);
    QPainterPath path;

    if (m_curveProperties.curve_paint_connection_line) {
        path.moveTo(pi1.pos());
        path.lineTo(pi2.pos());
        m_painter->drawPainterPath(path, pen);
        path = QPainterPath();
    }

    if (m_points.length() >= maxPoints) {
        // alpha * 0.2;
        path.moveTo(m_points.first());

        if (m_curveProperties.curve_smoothing) {
            path.quadTo(m_points.at(maxPoints / 2), m_points.last());
        }
        else {
            // control point is at 1/3 of the history, 2/3 of the history and endpoint at 3/3
            int step = maxPoints / 3;
            path.cubicTo(m_points.at(step), m_points.at(step + step), m_points.last());
        }

        qreal curveOpacity = m_curvesOpacityOption.apply(pi2, m_curveProperties.curve_curves_opacity);
        m_painter->setOpacity(qRound(255.0 * curveOpacity));
        m_painter->drawPainterPath(path, pen);
        m_painter->setOpacity(255); // full
    }
}
bool KisDuplicateOpSettings::mousePressEvent(const KisPaintInformation &info, Qt::KeyboardModifiers modifiers)
{
    bool ignoreEvent = true;
    if (modifiers == Qt::ControlModifier) {
        m_position = info.pos();
        m_isOffsetNotUptodate = true;
        ignoreEvent = false;
    } else {
        if (m_isOffsetNotUptodate) {
            m_offset = info.pos() - m_position;
            m_isOffsetNotUptodate = false;
        }
        ignoreEvent = true;
    }
    
    return ignoreEvent;
}
Example #12
0
QPainterPath KisLiquifyPaintop::brushOutline(const KisLiquifyProperties &props,
                                             const KisPaintInformation &info)
{
    const qreal diameter = props.size();
    const qreal reverseCoeff = props.reverseDirection() ? -1.0 : 1.0;

    QPainterPath outline;
    outline.addEllipse(-0.5 * diameter, -0.5 * diameter,
                       diameter, diameter);

    switch (props.mode()) {
    case KisLiquifyProperties::MOVE:
    case KisLiquifyProperties::SCALE:
        break;
    case KisLiquifyProperties::ROTATE: {
        QPainterPath p;
        p.lineTo(-3.0, 4.0);
        p.moveTo(0.0, 0.0);
        p.lineTo(-3.0, -4.0);

        QTransform S;
        if (diameter < 15.0) {
            const qreal scale = diameter / 15.0;
            S = QTransform::fromScale(scale, scale);
        }
        QTransform R;
        R.rotateRadians(-reverseCoeff * 0.5 * M_PI);
        QTransform T = QTransform::fromTranslate(0.5 * diameter, 0.0);

        p = (S * R * T).map(p);
        outline.addPath(p);

        break;
    }
    case KisLiquifyProperties::OFFSET: {
        qreal normalAngle = info.drawingAngle() + reverseCoeff * 0.5 * M_PI;

        QPainterPath p = KisAlgebra2D::smallArrow();

        const qreal offset = qMax(0.8 * diameter, 15.0);

        QTransform R;
        R.rotateRadians(normalAngle);
        QTransform T = QTransform::fromTranslate(offset, 0.0);
        p = (T * R).map(p);

        outline.addPath(p);

        break;
    }
    case KisLiquifyProperties::UNDO:
        break;
    case KisLiquifyProperties::N_MODES:
        qFatal("Not supported mode");
    }

    return outline;
}
void KisSketchPaintOp::updateBrushMask(const KisPaintInformation& info, qreal scale, qreal rotation){
    m_maskDab = m_dabCache->fetchDab(m_dab->colorSpace(), painter()->paintColor(), scale, scale,
                                     rotation, info);

    // update bounding box
    m_brushBoundingBox = m_maskDab->bounds();
    m_hotSpot = m_brush->hotSpot(scale,scale,rotation,info);
    m_brushBoundingBox.translate(info.pos() - m_hotSpot);
}
Example #14
0
void KisToolFreehandHelper::paintBezierCurve(int painterInfoId,
        const KisPaintInformation &pi1,
        const QPointF &control1,
        const QPointF &control2,
        const KisPaintInformation &pi2)
{
#ifdef DEBUG_BEZIER_CURVES
    KisPaintInformation tpi1;
    KisPaintInformation tpi2;

    tpi1 = pi1;
    tpi2 = pi2;

    tpi1.setPressure(0.3);
    tpi2.setPressure(0.3);

    paintLine(tpi1, tpi2);

    tpi1.setPressure(0.6);
    tpi2.setPressure(0.3);

    tpi1.setPos(pi1.pos());
    tpi2.setPos(control1);
    paintLine(tpi1, tpi2);

    tpi1.setPos(pi2.pos());
    tpi2.setPos(control2);
    paintLine(tpi1, tpi2);
#endif

    m_d->hasPaintAtLeastOnce = true;
    m_d->strokesFacade->addJob(m_d->strokeId,
                               new FreehandStrokeStrategy::Data(m_d->resources->currentNode(),
                                       painterInfoId,
                                       pi1, control1, control2, pi2));

    if(m_d->recordingAdapter) {
        m_d->recordingAdapter->addCurve(pi1, control1, control2, pi2);
    }
}
Example #15
0
bool KisDuplicateOpSettings::mousePressEvent(const KisPaintInformation &info, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode)
{
    bool ignoreEvent = true;

    if (modifiers & Qt::ControlModifier) {
        if (!m_sourceNode || !(modifiers & Qt::AltModifier)) {
            m_sourceNode = currentNode;
        }
        m_position = info.pos();
        m_isOffsetNotUptodate = true;
        ignoreEvent = false;
    }
    else {
        if (m_isOffsetNotUptodate) {
            m_offset = info.pos() - m_position;
            m_isOffsetNotUptodate = false;
        }
        ignoreEvent = true;
    }

    return ignoreEvent;
}
Example #16
0
void KisSketchPaintOp::updateBrushMask(const KisPaintInformation& info, qreal scale, qreal rotation)
{
    QRect dstRect;
    m_maskDab = m_dabCache->fetchDab(m_dab->colorSpace(),
                                     painter()->paintColor(),
                                     info.pos(),
                                     scale, scale, rotation,
                                     info, 1.0,
                                     &dstRect);

    m_brushBoundingBox = dstRect;
    m_hotSpot = QPointF(0.5 * m_brushBoundingBox.width(),
                        0.5 * m_brushBoundingBox.height());
}
Example #17
0
void KisToolLineHelper::addPoint(KoPointerEvent *event, const QPointF &overridePos)
{
    if (!m_d->enabled) return;

    KisPaintInformation pi =
            m_d->infoBuilder->continueStroke(event, elapsedStrokeTime());

    if (!m_d->useSensors) {
        pi = KisPaintInformation(pi.pos());
    }

    if (!overridePos.isNull()) {
        pi.setPos(overridePos);
    }

    if (m_d->linePoints.size() > 1) {
        const QPointF startPos = m_d->linePoints.first().pos();
        const QPointF endPos = pi.pos();
        const qreal maxDistance = kisDistance(startPos, endPos);
        const QPointF unit = (endPos - startPos) / maxDistance;

        QVector<KisPaintInformation>::iterator it = m_d->linePoints.begin();
        ++it;
        while (it != m_d->linePoints.end()) {
            qreal dist = kisDistance(startPos, it->pos());
            if (dist < maxDistance) {
                QPointF pos = startPos + unit * dist;
                it->setPos(pos);
                ++it;
            } else {
                it = m_d->linePoints.erase(it);
            }
        }
    }

    m_d->linePoints.append(pi);
}
Example #18
0
void KisParticlePaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance)
{
    Q_UNUSED(currentDistance);
    if (!painter()) return;

    if (!m_dab) {
        m_dab = source()->createCompositionSourceDevice();
    }
    else {
        m_dab->clear();
    }


    if (m_first) {
        m_particleBrush.setInitialPosition(pi1.pos());
        m_first = false;
    }

    m_particleBrush.draw(m_dab, painter()->paintColor(), pi2.pos());
    QRect rc = m_dab->extent();

    painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height());
    painter()->renderMirrorMask(rc, m_dab);
}
Example #19
0
void KisDabCache::postProcessDab(KisFixedPaintDeviceSP dab,
                                 const KisPaintInformation& info)
{
    if (m_d->mirrorOption) {
        MirrorProperties mirror = m_d->mirrorOption->apply(info);
        dab->mirror(mirror.horizontalMirror, mirror.verticalMirror);
    }

    if (m_d->sharpnessOption) {
        m_d->sharpnessOption->applyThreshold(dab);
    }

    if (m_d->textureOption) {
        m_d->textureOption->apply(dab, info.pos().toPoint(), info);
    }
}
Example #20
0
QPainterPath KisExperimentPaintOpSettings::brushOutline(const KisPaintInformation &info, KisPaintOpSettings::OutlineMode mode) const
{
    QPainterPath path;
    if (mode == CursorIsOutline) {

        QRectF ellipse(0, 0, 3, 3);
        ellipse.translate(-ellipse.center());
        path.addEllipse(ellipse);

        ellipse.setRect(0,0, 12, 12);
        ellipse.translate(-ellipse.center());
        path.addEllipse(ellipse);

        path.translate(info.pos());
    }
    return path;
}
qreal KisDynamicSensorFade::value(const KisPaintInformation&  pi)
{
    if (pi.isHoveringMode()) return 1.0;

    if (m_counter > m_length) {
        if (m_periodic) {
            reset();
        }
        else {
            m_counter = m_length;
        }
    }

    qreal result =  1.0 - (m_counter / qreal(m_length));
    m_counter++;

    return result;
}
Example #22
0
void SprayBrush::paintMetaballs(KisPaintDeviceSP dev, const KisPaintInformation &info, const KoColor &painterColor) {
    // TODO: make adjustable?
    qreal MIN_TRESHOLD = m_mintresh;
    qreal MAX_TRESHOLD = m_maxtresh;

//    dbgPlugins << "MAX " << MAX_TRESHOLD;
//    dbgPlugins << "MIN " << MIN_TRESHOLD;

    KoColor color = painterColor;
    qreal posX = info.pos().x();
    qreal posY = info.pos().y();

    //int points = m_coverage * (m_radius * m_radius * M_PI);
    qreal ballRadius = m_width * 0.5;

    // generate metaballs
    QList<Metaball> list;
    for (int i = 0; i < m_particlesCount ; i++){
        qreal x = (2 * drand48() * m_radius) - m_radius;
        qreal y = (2 * drand48() * m_radius) - m_radius;
        list.append(
                    Metaball( x, 
                              y ,
                              drand48() *  ballRadius)
                    );
    }

 
    // paint it
    KisRandomAccessor accessor = dev->createRandomAccessor(0, 0);

    qreal sum = 0.0;
    m_computeArea.translate( -qRound(posX), -qRound(posY) );
    for (int y = m_computeArea.y(); y <= m_computeArea.height(); y++){
        for (int x = m_computeArea.x() ; x <= m_computeArea.width(); x++){

            sum = 0.0;        

            for (int i = 0; i < m_particlesCount; i++){
                sum += list[i].equation(x, y );
            }
           
            if (sum >= MIN_TRESHOLD && sum <= MAX_TRESHOLD){
                    if (sum < 0.0) sum = 0.0;
                    if (sum > 1.0) sum = 1.0;

                    color.setOpacity(OPACITY_OPAQUE * sum);
                    accessor.moveTo( x + posX ,y + posY );
                    memcpy(accessor.rawData(), color.data(), dev->colorSpace()->pixelSize() );
            }
        }
    }
    m_computeArea.translate( qRound(posX), qRound(posY) );

#if 0        
        KisPainter dabPainter(dev);
        dabPainter.setFillColor(color);
        dabPainter.setPaintColor(color);
        dabPainter.setFillStyle(KisPainter::FillStyleForegroundColor);

        for (int i = 0; i < m_particlesCount; i++){
                qreal x = list[i].x() + posX;
                qreal y = list[i].y() + posY;
                dabPainter.paintEllipse(x, y, list[i].radius() * 2,list[i].radius() * 2);
        }
#endif

}
Example #23
0
void KisFilterOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()) {
        return;
    }

    KisFilterSP filter = settings->filter();
    if (!filter) {
        return;
    }

    if (!source()) {
        return;
    }

    KisBrushSP brush = m_brush;;
    if (!brush) return;

    KisPaintInformation adjustedInfo = settings->m_optionsWidget->m_sizeOption->apply(info);
    if (! brush->canPaintFor(adjustedInfo))
        return;

    double pScale = KisPaintOp::scaleForPressure(adjustedInfo.pressure());   // TODO: why is there scale and pScale that seems to contains the same things ?
    QPointF hotSpot = brush->hotSpot(pScale, pScale);
    QPointF pt = info.pos() - hotSpot;


    // Split the coordinates into integer plus fractional parts. The integer
    // is where the dab will be positioned and the fractional part determines
    // the sub-pixel positioning.
    qint32 x;
    double xFraction;
    qint32 y;
    double yFraction;

    splitCoordinate(pt.x(), &x, &xFraction);
    splitCoordinate(pt.y(), &y, &yFraction);

    double scale = KisPaintOp::scaleForPressure(adjustedInfo.pressure());

    qint32 maskWidth = brush->maskWidth(scale, 0.0);
    qint32 maskHeight = brush->maskHeight(scale, 0.0);

    // Filter the paint device
    filter->process(KisConstProcessingInformation(source(), QPoint(x, y)),
                    KisProcessingInformation(m_tmpDevice, QPoint(0, 0)),
                    QSize(maskWidth, maskHeight),
                    settings->filterConfig(), 0);

    // Apply the mask on the paint device (filter before mask because edge pixels may be important)

    KisFixedPaintDeviceSP fixedDab = new KisFixedPaintDevice(m_tmpDevice->colorSpace());
    fixedDab->setRect(m_tmpDevice->extent());
    fixedDab->initialize();

    m_tmpDevice->readBytes(fixedDab->data(), fixedDab->bounds());
    brush->mask(fixedDab, scale, scale, 0.0, info, xFraction, yFraction);
    m_tmpDevice->writeBytes(fixedDab->data(), fixedDab->bounds());

    if (!settings->ignoreAlpha()) {
        KisHLineIteratorPixel itTmpDev = m_tmpDevice->createHLineIterator(0, 0, maskWidth);
        KisHLineIteratorPixel itSrc = source()->createHLineIterator(x, y, maskWidth);
        const KoColorSpace* cs = m_tmpDevice->colorSpace();
        for (int y = 0; y < maskHeight; ++y) {
            while (!itTmpDev.isDone()) {
                quint8 alphaTmpDev = cs->alpha(itTmpDev.rawData());
                quint8 alphaSrc = cs->alpha(itSrc.rawData());

                cs->setAlpha(itTmpDev.rawData(), qMin(alphaTmpDev, alphaSrc), 1);
                ++itTmpDev;
                ++itSrc;
            }
            itTmpDev.nextRow();
            itSrc.nextRow();
        }
    }

    // Blit the paint device onto the layer
    QRect dabRect = QRect(0, 0, maskWidth, maskHeight);
    QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height());

    if (painter()->bounds().isValid()) {
        dstRect &= painter()->bounds();
    }
    if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return;

    qint32 sx = dstRect.x() - x;
    qint32 sy = dstRect.y() - y;
    qint32 sw = dstRect.width();
    qint32 sh = dstRect.height();

    painter()->bitBlt(dstRect.x(), dstRect.y(), m_tmpDevice, sx, sy, sw, sh);

}
QPainterPath KisCurrentOutlineFetcher::fetchOutline(const KisPaintInformation &info,
                                                    const KisPaintOpSettings *settings,
                                                    const QPainterPath &originalOutline,
                                                    qreal additionalScale,
                                                    qreal additionalRotation,
                                                    bool tilt, qreal tiltcenterx, qreal tiltcentery) const
{
    if (d->isDirty) {
        if (d->sizeOption) {
            d->sizeOption->readOptionSetting(settings);
            d->sizeOption->resetAllSensors();
        }

        if (d->rotationOption) {
            d->rotationOption->readOptionSetting(settings);
            d->rotationOption->resetAllSensors();
        }

        if (d->mirrorOption) {
            d->mirrorOption->readOptionSetting(settings);
            d->mirrorOption->resetAllSensors();
        }

        d->isDirty = false;
    }

    qreal scale = additionalScale;
    qreal rotation = additionalRotation;
    MirrorProperties mirrorProperties;
    bool needsUpdate = false;

    // Randomized rotation at full speed looks noisy, so slow it down
    if (d->lastUpdateTime.elapsed() > NOISY_UPDATE_SPEED) {
        needsUpdate = true;
        d->lastUpdateTime.restart();
    }

    if (d->sizeOption && tilt == false) {
        if (!d->sizeOption->isRandom() || needsUpdate) {
            d->lastSizeApplied = d->sizeOption->apply(info);
        }
        scale *= d->lastSizeApplied;
    }

    if (d->rotationOption && tilt == false) {
        if (!d->rotationOption->isRandom() || needsUpdate) {
            d->lastRotationApplied = d->rotationOption->apply(info);
        }
        rotation += d->lastRotationApplied;
    } else if (d->rotationOption && tilt == true) {
        rotation += settings->getDouble("runtimeCanvasRotation", 0.0) * M_PI / 180.0;
    }

    qreal xFlip = 1.0;
    qreal yFlip = 1.0;

    if (d->mirrorOption) {
        if (!d->mirrorOption->isRandom() || needsUpdate) {
            d->lastMirrorApplied = d->mirrorOption->apply(info);
        }

        if (d->lastMirrorApplied.coordinateSystemFlipped) {
            rotation = 2 * M_PI - rotation;
        }

        if (d->lastMirrorApplied.horizontalMirror) {
            xFlip = -1.0;
        }

        if (d->lastMirrorApplied.verticalMirror) {
            yFlip = -1.0;
        }
    }


    QTransform rot;
    rot.rotateRadians(-rotation);

    QPointF hotSpot = originalOutline.boundingRect().center();
    if (tilt==true) { 
        hotSpot.setX(tiltcenterx);hotSpot.setY(tiltcentery);
    }
    QTransform T1 = QTransform::fromTranslate(-hotSpot.x(), -hotSpot.y());
    QTransform T2 = QTransform::fromTranslate(info.pos().x(), info.pos().y());
    QTransform S  = QTransform::fromScale(xFlip * scale, yFlip * scale);

    return (T1 * rot * S * T2).map(originalOutline);
}
Example #25
0
void SprayBrush::paint(KisPaintDeviceSP dab, KisPaintDeviceSP source,
                       const KisPaintInformation& info, qreal rotation, qreal scale,
                       const KoColor &color, const KoColor &bgColor)
{
    // initializing painter
    if (!m_painter) {
        m_painter = new KisPainter(dab);
        m_painter->setFillStyle(KisPainter::FillStyleForegroundColor);
        m_painter->setMaskImageSize(m_shapeProperties->width, m_shapeProperties->height);
        m_dabPixelSize = dab->colorSpace()->pixelSize();
        if (m_colorProperties->useRandomHSV) {
            m_transfo = dab->colorSpace()->createColorTransformation("hsv_adjustment", QHash<QString, QVariant>());
        }

        m_brushQImage = m_shapeProperties->image;
        if (!m_brushQImage.isNull()) {
            m_brushQImage = m_brushQImage.scaled(m_shapeProperties->width, m_shapeProperties->height);
        }
        m_imageDevice = new KisPaintDevice(dab->colorSpace());
    }


    qreal x = info.pos().x();
    qreal y = info.pos().y();
    KisRandomAccessorSP accessor = dab->createRandomAccessorNG(qRound(x), qRound(y));

    Q_ASSERT(color.colorSpace()->pixelSize() == dab->pixelSize());
    m_inkColor = color;
    KisCrossDeviceColorPicker colorPicker(source, m_inkColor);

    // apply size sensor
    m_radius = m_properties->radius * scale;

    // jitter movement
    if (m_properties->jitterMovement) {
        x = x + ((2 * m_radius * drand48()) - m_radius) * m_properties->amount;
        y = y + ((2 * m_radius * drand48()) - m_radius) * m_properties->amount;
    }

    // this is wrong for every shape except pixel and anti-aliased pixel


    if (m_properties->useDensity) {
        m_particlesCount = (m_properties->coverage * (M_PI * m_radius * m_radius));
    }
    else {
        m_particlesCount = m_properties->particleCount;
    }

    QHash<QString, QVariant> params;
    qreal nx, ny;
    int ix, iy;

    qreal angle;
    qreal length;
    qreal rotationZ = 0.0;
    qreal particleScale = 1.0;

    bool shouldColor = true;
    if (m_colorProperties->fillBackground) {
        m_painter->setPaintColor(bgColor);
        paintCircle(m_painter, x, y, m_radius);
    }

    QTransform m;
    m.reset();
    m.rotateRadians(-rotation + deg2rad(m_properties->brushRotation));
    m.scale(m_properties->scale, m_properties->scale);

    for (quint32 i = 0; i < m_particlesCount; i++) {
        // generate random angle
        angle = drand48() * M_PI * 2;

        // generate random length
        if (m_properties->gaussian) {
            length = qBound<qreal>(0.0, m_rand->nextGaussian(0.0, 0.50) , 1.0);
        }
        else {
            length = drand48();
        }

        if (m_shapeDynamicsProperties->enabled) {
            // rotation
            rotationZ = rotationAngle();

            if (m_shapeDynamicsProperties->followCursor) {

                rotationZ = linearInterpolation(rotationZ, angle, m_shapeDynamicsProperties->followCursorWeigth);
            }


            if (m_shapeDynamicsProperties->followDrawingAngle) {

                rotationZ = linearInterpolation(rotationZ, info.drawingAngle(), m_shapeDynamicsProperties->followDrawingAngleWeight);
            }

            // random size - scale
            if (m_shapeDynamicsProperties->randomSize) {
                particleScale = drand48();
            }
        }
        // generate polar coordinate
        nx = (m_radius * cos(angle)  * length);
        ny = (m_radius * sin(angle)  * length);

        // compute the height of the ellipse
        ny *= m_properties->aspect;

        // transform
        m.map(nx, ny, &nx, &ny);

        // color transformation

        if (shouldColor) {
            if (m_colorProperties->sampleInputColor) {
                colorPicker.pickOldColor(nx + x, ny + y, m_inkColor.data());
            }

            // mix the color with background color
            if (m_colorProperties->mixBgColor) {
                KoMixColorsOp * mixOp = dab->colorSpace()->mixColorsOp();

                const quint8 *colors[2];
                colors[0] = m_inkColor.data();
                colors[1] = bgColor.data();

                qint16 colorWeights[2];
                int MAX_16BIT = 255;
                qreal blend = info.pressure();

                colorWeights[0] = static_cast<quint16>(blend * MAX_16BIT);
                colorWeights[1] = static_cast<quint16>((1.0 - blend) * MAX_16BIT);
                mixOp->mixColors(colors, colorWeights, 2, m_inkColor.data());
            }

            if (m_colorProperties->useRandomHSV && m_transfo) {
                params["h"] = (m_colorProperties->hue / 180.0) * drand48();
                params["s"] = (m_colorProperties->saturation / 100.0) * drand48();
                params["v"] = (m_colorProperties->value / 100.0) * drand48();
                m_transfo->setParameters(params);
                m_transfo->transform(m_inkColor.data(), m_inkColor.data() , 1);
            }

            if (m_colorProperties->useRandomOpacity) {
                quint8 alpha = qRound(drand48() * OPACITY_OPAQUE_U8);
                m_inkColor.setOpacity(alpha);
                m_painter->setOpacity(alpha);
            }

            if (!m_colorProperties->colorPerParticle) {
                shouldColor = false;
            }
            m_painter->setPaintColor(m_inkColor);
        }

        qreal jitteredWidth = qMax(qreal(1.0), m_shapeProperties->width * particleScale);
        qreal jitteredHeight = qMax(qreal(1.0), m_shapeProperties->height * particleScale);

        if (m_shapeProperties->enabled){
        switch (m_shapeProperties->shape){
            // ellipse
            case 0:
            {
                if (m_shapeProperties->width == m_shapeProperties->height){
                    paintCircle(m_painter, nx + x, ny + y, qRound(jitteredWidth * 0.5));
                }
                else {
                    paintEllipse(m_painter, nx + x, ny + y, qRound(jitteredWidth * 0.5) , qRound(jitteredHeight * 0.5), rotationZ);
                }
                break;
            }
            // rectangle
            case 1:
            {
                paintRectangle(m_painter, nx + x, ny + y, qRound(jitteredWidth) , qRound(jitteredHeight), rotationZ);
                break;
            }
            // wu-particle
            case 2: {
                paintParticle(accessor, m_inkColor, nx + x, ny + y);
                break;
            }
            // pixel
            case 3: {
                ix = qRound(nx + x);
                iy = qRound(ny + y);
                accessor->moveTo(ix, iy);
                memcpy(accessor->rawData(), m_inkColor.data(), m_dabPixelSize);
                break;
            }
            case 4: {
                if (!m_brushQImage.isNull()) {

                    QTransform m;
                    m.rotate(rad2deg(rotationZ));

                    if (m_shapeDynamicsProperties->randomSize) {
                        m.scale(particleScale, particleScale);
                    }
                    m_transformed = m_brushQImage.transformed(m, Qt::SmoothTransformation);
                    m_imageDevice->convertFromQImage(m_transformed, 0);
                    KisRandomAccessorSP ac = m_imageDevice->createRandomAccessorNG(0, 0);
                    QRect rc = m_transformed.rect();

                    if (m_colorProperties->useRandomHSV && m_transfo) {

                        for (int y = rc.y(); y < rc.y() + rc.height(); y++) {
                            for (int x = rc.x(); x < rc.x() + rc.width(); x++) {
                                ac->moveTo(x, y);
                                m_transfo->transform(ac->rawData(), ac->rawData() , 1);
                            }
                        }
                    }

                    ix = qRound(nx + x - rc.width() * 0.5);
                    iy = qRound(ny + y - rc.height() * 0.5);
                    m_painter->bitBlt(QPoint(ix, iy), m_imageDevice, rc);
                    m_imageDevice->clear();
                    break;
                }
            }
            }
            // Auto-brush
        }
        else {
            QPointF hotSpot = m_brush->hotSpot(particleScale, particleScale, -rotationZ, info);
            QPointF pos(nx + x, ny + y);
            QPointF pt = pos - hotSpot;

            qint32 ix;
            qreal xFraction;
            qint32 iy;
            qreal yFraction;

            KisPaintOp::splitCoordinate(pt.x(), &ix, &xFraction);
            KisPaintOp::splitCoordinate(pt.y(), &iy, &yFraction);

            //KisFixedPaintDeviceSP dab;
            if (m_brush->brushType() == IMAGE ||
                    m_brush->brushType() == PIPE_IMAGE) {
                m_fixedDab = m_brush->paintDevice(m_fixedDab->colorSpace(), particleScale, -rotationZ, info, xFraction, yFraction);

                if (m_colorProperties->useRandomHSV && m_transfo) {
                    quint8 * dabPointer = m_fixedDab->data();
                    int pixelCount = m_fixedDab->bounds().width() * m_fixedDab->bounds().height();
                    m_transfo->transform(dabPointer, dabPointer, pixelCount);
                }

            }
            else {
                m_brush->mask(m_fixedDab, m_inkColor, particleScale, particleScale, -rotationZ, info, xFraction, yFraction);
            }
            m_painter->bltFixed(QPoint(ix, iy), m_fixedDab, m_fixedDab->bounds());
        }
    }
    // recover from jittering of color,
    // m_inkColor.opacity is recovered with every paint
}
Example #26
0
void KisDuplicateOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()) return;

    if (!m_duplicateStartIsSet) {
        m_duplicateStartIsSet = true;
        m_duplicateStart = info.pos();
    }

    bool heal = settings->healing();

    if (!source()) return;

    KisBrushSP brush = m_brush;
    if (!brush) return;
    if (! brush->canPaintFor(info))
        return;

    double scale = KisPaintOp::scaleForPressure(info.pressure());
    QPointF hotSpot = brush->hotSpot(scale, scale);
    QPointF pt = info.pos() - hotSpot;

    // Split the coordinates into integer plus fractional parts. The integer
    // is where the dab will be positioned and the fractional part determines
    // the sub-pixel positioning.
    qint32 x;
    double xFraction;
    qint32 y;
    double yFraction;

    splitCoordinate(pt.x(), &x, &xFraction);
    splitCoordinate(pt.y(), &y, &yFraction);
    xFraction = yFraction = 0.0;

    QPointF srcPointF = pt - settings->offset();
    QPoint srcPoint = QPoint(x - static_cast<qint32>(settings->offset().x()),
                             y - static_cast<qint32>(settings->offset().y()));


    qint32 sw = brush->maskWidth(scale, 0.0);
    qint32 sh = brush->maskHeight(scale, 0.0);

    if (srcPoint.x() < 0)
        srcPoint.setX(0);

    if (srcPoint.y() < 0)
        srcPoint.setY(0);
    if (!(m_srcdev && !(*m_srcdev->colorSpace() == *source()->colorSpace()))) {
        m_srcdev = new KisPaintDevice(source()->colorSpace());
    }
    Q_CHECK_PTR(m_srcdev);

    // Perspective correction ?
    KisPainter copyPainter(m_srcdev);
    KisImageSP image = settings->m_image;
    if (settings->perspectiveCorrection() && image && image->perspectiveGrid()->countSubGrids() == 1) {
        Matrix3qreal startM = Matrix3qreal::Identity();
        Matrix3qreal endM = Matrix3qreal::Identity();

        // First look for the grid corresponding to the start point
        KisSubPerspectiveGrid* subGridStart = *image->perspectiveGrid()->begin();
        QRect r = QRect(0, 0, image->width(), image->height());

#if 1
        if (subGridStart) {
            startM = KisPerspectiveMath::computeMatrixTransfoFromPerspective(r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight());
        }
#endif
#if 1
        // Second look for the grid corresponding to the end point
        KisSubPerspectiveGrid* subGridEnd = *image->perspectiveGrid()->begin();
        if (subGridEnd) {
            endM = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r);
        }
#endif

        // Compute the translation in the perspective transformation space:
        QPointF positionStartPaintingT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart));
        QPointF duplicateStartPositionT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart) - QPointF(settings->offset()));
        QPointF translat = duplicateStartPositionT - positionStartPaintingT;
        KisRectIteratorPixel dstIt = m_srcdev->createRectIterator(0, 0, sw, sh);
        KisRandomSubAccessorPixel srcAcc = source()->createRandomSubAccessor();
        //Action
        while (!dstIt.isDone()) {
            if (dstIt.isSelected()) {
                QPointF p =  KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, QPointF(dstIt.x() + x, dstIt.y() + y)) + translat);
                srcAcc.moveTo(p);
                srcAcc.sampledOldRawData(dstIt.rawData());
            }
            ++dstIt;
        }


    } else {
        // Or, copy the source data on the temporary device:
        copyPainter.setCompositeOp(COMPOSITE_COPY);
        copyPainter.bitBlt(0, 0, source(), srcPoint.x(), srcPoint.y(), sw, sh);
        copyPainter.end();
    }

    // heal ?

    if (heal) {
        quint16 dataDevice[4];
        quint16 dataSrcDev[4];
        double* matrix = new double[ 3 * sw * sh ];
        // First divide
        const KoColorSpace* deviceCs = source()->colorSpace();
        KisHLineConstIteratorPixel deviceIt = source()->createHLineConstIterator(x, y, sw);
        KisHLineIteratorPixel srcDevIt = m_srcdev->createHLineIterator(0, 0, sw);
        double* matrixIt = &matrix[0];
        for (int j = 0; j < sh; j++) {
            for (int i = 0; !srcDevIt.isDone(); i++) {
                deviceCs->toLabA16(deviceIt.rawData(), (quint8*)dataDevice, 1);
                deviceCs->toLabA16(srcDevIt.rawData(), (quint8*)dataSrcDev, 1);
                // Division
                for (int k = 0; k < 3; k++) {
                    matrixIt[k] = dataDevice[k] / (double)qMax((int)dataSrcDev [k], 1);
                }
                ++deviceIt;
                ++srcDevIt;
                matrixIt += 3;
            }
            deviceIt.nextRow();
            srcDevIt.nextRow();
        }
        // Minimize energy
        {
            int iter = 0;
            double err;
            double* solution = new double [ 3 * sw * sh ];
            do {
                err = minimizeEnergy(&matrix[0], &solution[0], sw, sh);
                memcpy(&matrix[0], &solution[0], sw * sh * 3 * sizeof(double));
                iter++;
            } while (err < 0.00001 && iter < 100);
            delete [] solution;
        }

        // Finaly multiply
        deviceIt = source()->createHLineIterator(x, y, sw);
        srcDevIt = m_srcdev->createHLineIterator(0, 0, sw);
        matrixIt = &matrix[0];
        for (int j = 0; j < sh; j++) {
            for (int i = 0; !srcDevIt.isDone(); i++) {
                deviceCs->toLabA16(deviceIt.rawData(), (quint8*)dataDevice, 1);
                deviceCs->toLabA16(srcDevIt.rawData(), (quint8*)dataSrcDev, 1);
                // Multiplication
                for (int k = 0; k < 3; k++) {
                    dataSrcDev[k] = (int)CLAMP(matrixIt[k] * qMax((int) dataSrcDev[k], 1), 0, 65535);
                }
                deviceCs->fromLabA16((quint8*)dataSrcDev, srcDevIt.rawData(), 1);
                ++deviceIt;
                ++srcDevIt;
                matrixIt += 3;
            }
            deviceIt.nextRow();
            srcDevIt.nextRow();
        }
        delete [] matrix;
    }

    KisFixedPaintDeviceSP fixedDab = new KisFixedPaintDevice(m_srcdev->colorSpace());
    fixedDab->setRect(QRect(0, 0, sw, sh));
    fixedDab->initialize();

    m_srcdev->readBytes(fixedDab->data(), fixedDab->bounds());
    brush->mask(fixedDab, scale, scale, 0.0, info, xFraction, yFraction);
    m_srcdev->writeBytes(fixedDab->data(), fixedDab->bounds());

    QRect dabRect = QRect(0, 0, brush->maskWidth(scale, 0.0), brush->maskHeight(scale, 0.0));
    QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height());

    if (painter()->bounds().isValid()) {
        dstRect &= painter()->bounds();
    }

    if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return;

    qint32 sx = dstRect.x() - x;
    qint32 sy = dstRect.y() - y;
    sw = dstRect.width();
    sh = dstRect.height();

    painter()->bitBlt(dstRect.x(), dstRect.y(), m_srcdev, sx, sy, sw, sh);


}
Example #27
0
KisSpacingInformation KisFilterOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()) {
        return KisSpacingInformation(1.0);
    }

    if (!m_filter) {
        return KisSpacingInformation(1.0);
    }

    if (!source()) {
        return KisSpacingInformation(1.0);
    }

    KisBrushSP brush = m_brush;
    if (!brush) return KisSpacingInformation(1.0);

    if (! brush->canPaintFor(info))
        return KisSpacingInformation(1.0);

    qreal scale = m_sizeOption.apply(info);
    if (checkSizeTooSmall(scale)) return KisSpacingInformation();

    setCurrentScale(scale);

    qreal rotation = m_rotationOption.apply(info);

    static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8();
    static KoColor color(Qt::black, cs);

    QRect dstRect;
    KisFixedPaintDeviceSP dab =
        m_dabCache->fetchDab(cs, color, info.pos(),
                             scale, scale, rotation,
                             info, 1.0,
                             &dstRect);

    if (dstRect.isEmpty()) return KisSpacingInformation(1.0);

    QRect dabRect = dab->bounds();

    // sanity check
    Q_ASSERT(dstRect.size() == dabRect.size());


    // Filter the paint device
    QRect neededRect = m_filter->neededRect(dstRect, m_filterConfiguration);

    KisPainter p(m_tmpDevice);
    if (!m_smudgeMode) {
        p.setCompositeOp(COMPOSITE_COPY);
    }
    p.bitBltOldData(neededRect.topLeft() - dstRect.topLeft(), source(), neededRect);

    KisTransaction transaction(m_tmpDevice);
    m_filter->process(m_tmpDevice, dabRect, m_filterConfiguration, 0);
    transaction.end();


    painter()->
    bitBltWithFixedSelection(dstRect.x(), dstRect.y(),
                             m_tmpDevice, dab,
                             0, 0,
                             dabRect.x(), dabRect.y(),
                             dabRect.width(), dabRect.height());

    painter()->renderMirrorMaskSafe(dstRect, m_tmpDevice, 0, 0, dab,
                                    !m_dabCache->needSeparateOriginal());

    return effectiveSpacing(scale, rotation);
}
void KisSketchPaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance)
{
    Q_UNUSED(currentDistance);

    if (!m_brush || !painter()) return;

    if (!m_dab) {
        m_dab = source()->createCompositionSourceDevice();
        m_painter = new KisPainter(m_dab);
        m_painter->setPaintColor(painter()->paintColor());
    } else {
        m_dab->clear();
    }

    QPointF prevMouse = pi1.pos();
    QPointF mousePosition = pi2.pos();
    m_points.append(mousePosition);

    const double scale = m_sizeOption.apply(pi2);
    const double rotation = m_rotationOption.apply(pi2);
    const double currentProbability = m_densityOption.apply(pi2, m_sketchProperties.probability);
    const double currentLineWidth = m_lineWidthOption.apply(pi2, m_sketchProperties.lineWidth);
    const double currentOffsetScale = m_offsetScaleOption.apply(pi2, m_sketchProperties.offset);

    if ((scale * m_brush->width()) <= 0.01 || (scale * m_brush->height()) <= 0.01) return;

    // shaded: does not draw this line, chrome does, fur does
    if (m_sketchProperties.makeConnection){
        drawConnection(prevMouse, mousePosition, currentLineWidth);
    }

    setCurrentScale(scale);
    setCurrentRotation(rotation);

    qreal thresholdDistance = 0.0;

    // update the mask for simple mode only once
    // determine the radius
    if (m_count == 0 && m_sketchProperties.simpleMode){
        updateBrushMask(pi2,1.0,0.0);
        //m_radius = qMax(m_maskDab->bounds().width(),m_maskDab->bounds().height()) * 0.5;
        m_radius = 0.5 * qMax(m_brush->width(), m_brush->height());
    }

    if (!m_sketchProperties.simpleMode){
        updateBrushMask(pi2,scale,rotation);
        m_radius = qMax(m_maskDab->bounds().width(),m_maskDab->bounds().height()) * 0.5;
        thresholdDistance = pow(m_radius,2);
    }

    if (m_sketchProperties.simpleMode){
        // update the radius according scale in simple mode
        thresholdDistance = pow(m_radius * scale,2);
    }

    // determine density
    const qreal density = thresholdDistance * currentProbability;

    // probability behaviour
    qreal probability = 1.0 - currentProbability;

    QColor painterColor = painter()->paintColor().toQColor();
    QColor randomColor;
    KoColor color(m_dab->colorSpace());

    int w = m_maskDab->bounds().width();
    quint8 opacityU8 = 0;
    quint8 * pixel;
    qreal distance;
    QPoint  positionInMask;
    QPointF diff;

    int size = m_points.size();
    // MAIN LOOP
    for (int i = 0; i < size; i++) {
        diff = m_points.at(i) - mousePosition;
        distance = diff.x() * diff.x() + diff.y() * diff.y();

        // circle test
        bool makeConnection = false;
        if (m_sketchProperties.simpleMode){
            if (distance < thresholdDistance){
                makeConnection = true;
            }
        // mask test
        }else{

            if ( m_brushBoundingBox.contains( m_points.at(i) ) ){
                positionInMask = (diff + m_hotSpot).toPoint();
                pixel = m_maskDab->data() + ((positionInMask.y() * w + positionInMask.x()) * m_maskDab->pixelSize());
                opacityU8 = m_maskDab->colorSpace()->opacityU8( pixel );
                if (opacityU8 != 0){
                    makeConnection = true;
                }
            }

        }

        if (!makeConnection){
            // check next point
            continue;
        }

        if (m_sketchProperties.distanceDensity){
            probability =  distance / density;
        }

        // density check
        if (drand48() >= probability) {
            QPointF offsetPt = diff * currentOffsetScale;

            if (m_sketchProperties.randomRGB){
                // some color transformation per line goes here
                randomColor.setRgbF(drand48() * painterColor.redF(),
                                    drand48() * painterColor.greenF(),
                                    drand48() * painterColor.blueF()
                                    );
                color.fromQColor(randomColor);
                m_painter->setPaintColor(color);
            }

            // distance based opacity
            quint8 opacity = OPACITY_OPAQUE_U8;
            if (m_sketchProperties.distanceOpacity){
                opacity *= qRound((1.0 - (distance / thresholdDistance)));
            }

            if (m_sketchProperties.randomOpacity){
                opacity *= drand48();
            }

            m_painter->setOpacity(opacity);

            if (m_sketchProperties.magnetify) {
                drawConnection(mousePosition + offsetPt, m_points.at(i) - offsetPt, currentLineWidth);
            }else{
                drawConnection(mousePosition + offsetPt, mousePosition - offsetPt, currentLineWidth);
            }



        }
    }// end of MAIN LOOP

    m_count++;

    QRect rc = m_dab->extent();
    quint8 origOpacity = m_opacityOption.apply(painter(), pi2);

    painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height());
    painter()->renderMirrorMask(rc, m_dab);
    painter()->setOpacity(origOpacity);
}
Example #29
0
void SprayBrush::paint(KisPaintDeviceSP dev, const KisPaintInformation& info, const KoColor &color)
{
    qreal x = info.pos().x();
    qreal y = info.pos().y();

    // initializing painter
    KisPainter drawer(dev);
    drawer.setPaintColor(color);

    // jitter radius
    int tmpRadius = m_radius;
    if (m_jitterSize){
        m_radius = m_radius * drand48();
    }

    // jitter movement
    if (m_jitterMovement){
        x = x + (( 2 * m_radius * drand48() ) - m_radius) * m_amount;
        y = y + (( 2 * m_radius * drand48() ) - m_radius) * m_amount;
    }

    KisRandomAccessor accessor = dev->createRandomAccessor( qRound(x), qRound(y) );
    m_pixelSize = dev->colorSpace()->pixelSize();
    m_inkColor = color;
    m_counter++;

    // coverage: adaptively select how many objects are sprayed per paint
    if (m_useDensity){
        m_particlesCount = (m_coverage * (M_PI * m_radius * m_radius) );
    }

    // Metaballs are rendered little differently
    if (m_shape == 2 && m_object == 0){
        paintMetaballs(dev, info, color);
    }

    qreal nx, ny;
    int ix, iy;

    qreal angle;
    qreal lengthX;
    qreal lengthY;
    
    
    for (int i = 0; i < m_particlesCount; i++){
        // generate random angle
        angle = drand48() * M_PI * 2;
        // different X and Y length??
        lengthY = lengthX = drand48();
        // I hope we live the era where sin and cos is not slow for spray
        nx = (sin(angle) * m_radius * lengthX);
        ny = (cos(angle) * m_radius * lengthY);

        // transform
        nx *= m_scale;
        ny *= m_scale;

        // it is some shape (circle, ellipse, rectangle)
        if (m_object == 0)
        {
            // steps for single step in circle and ellipse
            int steps = 36;
            qreal random = drand48();       

            drawer.setFillColor(m_inkColor);
            drawer.setBackgroundColor(m_inkColor);
            drawer.setPaintColor(m_inkColor);
            // it is ellipse
            if (m_shape == 0){
                //  
                qreal ellipseA = m_width / 2.0;
                qreal ellipseB = m_height / 2.0;

                if (m_width == m_height)
                {
                    if (m_jitterShapeSize){
                        paintCircle(drawer, nx + x, ny + y, int((random * ellipseA) + 1.5) , steps);
                    } else{
                        paintCircle(drawer, nx + x, ny + y, qRound(ellipseA)  , steps);
                    }
                } else 
                {
                    if (m_jitterShapeSize){
                        paintEllipse(drawer, nx + x, ny + y,int((random * ellipseA) + 1.5) ,int((random * ellipseB) + 1.5), angle , steps);
                    } else{
                        paintEllipse(drawer, nx + x, ny + y, qRound(ellipseA), qRound(ellipseB), angle , steps);
                    }
                }
            } else if (m_shape == 1)
            {
                if (m_jitterShapeSize){
                    paintRectangle(drawer, nx + x, ny + y,int((random * m_width) + 1.5) ,int((random * m_height) + 1.5), angle , steps);
                } else{
                    paintRectangle(drawer, nx + x, ny + y, qRound(m_width), qRound(m_height), angle , steps);
                }
            }    
        // it is pixel particle
        }else if (m_object == 1){
            paintParticle(accessor,m_inkColor,nx + x, ny + y);
        }
        // it is pixel
        else if (m_object == 2)
        {
            ix = qRound(nx + x);
            iy = qRound(ny + y);
            accessor.moveTo(ix, iy);
            memcpy(accessor.rawData(), m_inkColor.data(), m_pixelSize);
        }
    }

    

    // hidden code for outline detection
    //m_inkColor.setOpacity(128);
    //paintOutline(dev,m_inkColor,x, y, m_radius * 2);

    // recover from jittering of color
    m_radius = tmpRadius;
}
Example #30
0
inline
KisFixedPaintDeviceSP KisDabCache::fetchDabCommon(const KoColorSpace *cs,
                                                  const KisColorSource *colorSource,
                                                  const KoColor& color,
                                                  double scaleX, double scaleY,
                                                  double angle,
                                                  const KisPaintInformation& info,
                                                  double subPixelX, double subPixelY,
                                                  qreal softnessFactor)
{
    if (!m_d->dab || !(*m_d->dab->colorSpace() == *cs)) {
        m_d->dab = new KisFixedPaintDevice(cs);
    } else {
        KisFixedPaintDeviceSP cachedDab =
            tryFetchFromCache(colorSource, color, scaleX, scaleY, angle,
                              info, subPixelX, subPixelY, softnessFactor);
        if (cachedDab) return cachedDab;
    }

    if (m_d->brush->brushType() == IMAGE || m_d->brush->brushType() == PIPE_IMAGE) {
        m_d->dab = m_d->brush->paintDevice(cs, scaleX, angle, info,
                                     subPixelX, subPixelY);
    }
    else {
        if (!colorSource) {
            KoColor paintColor = color;
            paintColor.convertTo(cs);

            *m_d->cachedDabParameters = getDabParameters(paintColor,
                                                      scaleX, scaleY,
                                                      angle, info,
                                                      subPixelX, subPixelY,
                                                      softnessFactor);

            m_d->brush->mask(m_d->dab, paintColor, scaleX, scaleY, angle,
                          info, subPixelX, subPixelY, softnessFactor);

        } else if (colorSource->isUniformColor()) {
            KoColor paintColor = colorSource->uniformColor();
            paintColor.convertTo(cs);

            *m_d->cachedDabParameters = getDabParameters(paintColor,
                                                      scaleX, scaleY,
                                                      angle, info,
                                                      subPixelX, subPixelY,
                                                      softnessFactor);

            m_d->brush->mask(m_d->dab, paintColor, scaleX, scaleY, angle,
                          info, subPixelX, subPixelY, softnessFactor);
        } else {
            if (!m_d->colorSourceDevice || !(*cs == *m_d->colorSourceDevice->colorSpace())) {
                m_d->colorSourceDevice = new KisPaintDevice(cs);
            } else {
                m_d->colorSourceDevice->clear();
            }

            QRect maskRect(0, 0, m_d->brush->maskWidth(scaleX, angle, info), m_d->brush->maskHeight(scaleY, angle, info));
            colorSource->colorize(m_d->colorSourceDevice, maskRect, info.pos().toPoint());
            delete m_d->colorSourceDevice->convertTo(cs);

            m_d->brush->mask(m_d->dab, m_d->colorSourceDevice, scaleX, scaleY, angle,
                          info, subPixelX, subPixelY, softnessFactor);
        }
    }

    if (needSeparateOriginal()) {
        if (!m_d->dabOriginal || !(*cs == *m_d->dabOriginal->colorSpace())) {
            m_d->dabOriginal = new KisFixedPaintDevice(cs);
        }

        *m_d->dabOriginal = *m_d->dab;
    }

    postProcessDab(m_d->dab, info);

    return m_d->dab;
}