void KisBidirectionalMixingOption::apply(KisPaintDeviceSP dab, KisPaintDeviceSP device, KisPainter* painter, qint32 sx, qint32 sy, qint32 sw, qint32 sh, quint8 pressure, const QRect& dstRect) { if (!isChecked()) return; KoColorSpace *cs = dab->colorSpace(); KisPaintDeviceSP canvas = new KisPaintDevice(cs); KisPainter p(canvas); p.setCompositeOp(COMPOSITE_COPY); p.bitBlt(sx, sy, device, dstRect.x(), dstRect.y(), sw, sh); int count = cs->channelCount(); KisRectIterator cit = canvas->createRectIterator(sx, sy, sw, sh); KisRectIterator dit = dab->createRectIterator(sx, sy, sw, sh); QVector<float> cc(count), dc(count); while (!cit.isDone()) { if (cs->alpha(dit.rawData()) > 10 && cs->alpha(cit.rawData()) > 10) { cs->normalisedChannelsValue(cit.rawData(), cc); cs->normalisedChannelsValue(dit.rawData(), dc); for (int i = 0; i < count; i++) dc[i] = (1.0 - 0.4 * pressure) * cc[i] + 0.4 * pressure * dc[i]; cs->fromNormalisedChannelsValue(dit.rawData(), dc); if (dit.x() == (int)(sw / 2) && dit.y() == (int)(sh / 2)) painter->setPaintColor(KoColor(dit.rawData(), cs)); } ++cit; ++dit; } }
quint8 KisPressureRateOption::apply( quint8 opacity, qint32 sw, qint32 sh, KisPaintDeviceSP srcdev, double pressure) const { opacity = rate(); if (isChecked()) { if (customCurve()) { opacity = qBound((qint32)OPACITY_TRANSPARENT, (qint32)(double(opacity) * scaleToCurve(pressure) / PRESSURE_DEFAULT), (qint32)OPACITY_OPAQUE); } else { opacity = qBound((qint32)OPACITY_TRANSPARENT, (qint32)(double(opacity) * pressure / PRESSURE_DEFAULT), (qint32)OPACITY_OPAQUE); } } #if 0 // TODO It's also applied in the smudgeop, do other paintops that require a rate // needs to do this to their srcDev ? KisRectIterator it = srcdev->createRectIterator(0, 0, sw, sh); KoColorSpace* cs = srcdev->colorSpace(); while (not it.isDone()) { cs->setAlpha(it.rawData(), (cs->alpha(it.rawData()) * opacity) / OPACITY_OPAQUE, 1); ++it; } return OPACITY_OPAQUE - opacity; #else return opacity; #endif }
void KisSmudgeOp::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()); 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); KisFixedPaintDeviceSP dab = 0; double scale = KisPaintOp::scaleForPressure(adjustedInfo.pressure()); 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 (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { dab = brush->image(device->colorSpace(), pScale, 0.0, adjustedInfo, xFraction, yFraction); dab->convertTo(KoColorSpaceRegistry::instance()->alpha8()); } else { dab = cachedDab(); KoColor color = painter()->paintColor(); dab->convertTo(KoColorSpaceRegistry::instance()->alpha8()); brush->mask(dab, color, scale, pScale, 0.0, info, xFraction, yFraction); } qint32 sw = dab->bounds().width(); qint32 sh = dab->bounds().height(); /* To smudge, one does the following: * at first, initialize a temporary paint device with a copy of the original (dab-sized piece, really). * all other times: reduce the transparency of the temporary paint device so as to let it mix gradually * combine the temp device with the piece the brush currently is 'painting', according to a mix (opacity) note that in the first step, this does the actual copying of the data * this combination is then composited upon the actual image TODO: what happened exactly in 1.6 (and should happen now) when the dab resizes halfway due to pressure? */ int opacity = OPACITY_OPAQUE; if (!m_firstRun) { opacity = settings->m_optionsWidget->m_rateOption->apply( opacity, sw, sh, m_srcdev, info.pressure() ); KisRectIterator it = m_srcdev->createRectIterator(0, 0, sw, sh); KoColorSpace* cs = m_srcdev->colorSpace(); while(!it.isDone()) { cs->setAlpha(it.rawData(), (cs->alpha(it.rawData()) * opacity) / OPACITY_OPAQUE, 1); ++it; } opacity = OPACITY_OPAQUE - opacity; } else { m_firstRun = false; } KisPainter copyPainter(m_srcdev); copyPainter.setOpacity(opacity); copyPainter.bitBlt(0, 0, device, pt.x(), pt.y(), sw, sh); copyPainter.end(); m_target = new KisPaintDevice(device->colorSpace()); // Looks hacky, but we lost bltMask, or the ability to easily convert alpha8 paintdev to selection? KisSelectionSP dabAsSelection = new KisSelection(); copyPainter.begin(dabAsSelection); copyPainter.setOpacity(OPACITY_OPAQUE); copyPainter.setCompositeOp(COMPOSITE_COPY); copyPainter.bltFixed(0, 0, dab, 0, 0, sw, sh); copyPainter.end(); copyPainter.begin(m_target); copyPainter.setCompositeOp(COMPOSITE_OVER); copyPainter.setSelection(dabAsSelection); copyPainter.bitBlt(0, 0, m_srcdev, 0, 0, sw, sh); copyPainter.end(); qint32 sx = dstRect.x() - x; qint32 sy = dstRect.y() - y; sw = dstRect.width(); sh = dstRect.height(); painter()->bitBlt(dstRect.x(), dstRect.y(), m_target, sx, sy, sw, sh); }