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); }