AGENTS and TASKS for 13.10, 13.11, 13.12; liveFolderMaskClip beside drawMaskAlone

This commit is contained in:
ZacharyZhang-NY committed 2026-10-01 18:08:33 -04:00
1 parent e243751f64
commit f91849ade5
6 files changed
+76 -65

No files matched your search

-23
View File
@@ -1,23 +0,0 @@
#include "Rendering/EditorCanvas.h"
// Swift's drawMaskAlone: gray across the canvas, edge tone past it.
void CanvasView::drawMaskAlone(const ImageLayer &layer, const CanvasDocument &document, double scale, const Center &center, QPainter &context)
{
const LayerMask &mask = layer.mask.value();
const int tone = qRound(LayerMask::background(mask.asset.thumbnail) * 255);
context.fillRect(QRectF(center(QPointF(0, 0)), document.size() * scale), QColor(tone, tone, tone));
const std::optional<GradientEdit> &gradient = m_session.gradientEdit();
const BrushStroke *stroke = m_session.brushStroke() ? m_session.brushStroke() : gradient ? gradient->raster.get() : nullptr;
// A stroke or gradient laid into it shows at once.
if (stroke && stroke->isMask && stroke->layer.id == layer.id) {
const LayerTransform &placed = stroke->paintTransform;
const std::shared_ptr<const RasterSnapshot> &raster = mask.asset.raster;
LayerRenderer::drawBrushPreview(raster ? QImage() : mask.asset.image(), placed, center(placed.center()), context, {.scale = scale},
{.patches = stroke->patches(), .pixelWidth = stroke->width, .pixelHeight = stroke->height,
.paintingMask = false, .sourceRect = stroke->sourceRect, .raster = raster});
return;
}
// Where a transform drag shows it, as the composite.
const LayerTransform placed = m_session.displayedMaskPlacement(layer).value_or(m_session.displayedTransform(layer));
LayerRenderer::draw(mask.asset.image(), placed, center(placed.center()), context, {.scale = scale});
}
+65
View File
@@ -0,0 +1,65 @@
#include "Rendering/EditorCanvas.h"
#include "IO/ImageExporter.h"
#include "Rendering/DownsampleCache.h"
#include "Rendering/LayerRenderer.h"
#include "Rendering/RasterSnapshot.h"
#include <QPainter>
// Swift's drawMaskAlone: gray across the canvas, edge tone past it.
void CanvasView::drawMaskAlone(const ImageLayer &layer, const CanvasDocument &document, double scale, const Center &center, QPainter &context)
{
const LayerMask &mask = layer.mask.value();
const int tone = qRound(LayerMask::background(mask.asset.thumbnail) * 255);
context.fillRect(QRectF(center(QPointF(0, 0)), document.size() * scale), QColor(tone, tone, tone));
const std::optional<GradientEdit> &gradient = m_session.gradientEdit();
const BrushStroke *stroke = m_session.brushStroke() ? m_session.brushStroke() : gradient ? gradient->raster.get() : nullptr;
// A stroke or gradient laid into it shows at once.
if (stroke && stroke->isMask && stroke->layer.id == layer.id) {
const LayerTransform &placed = stroke->paintTransform;
const std::shared_ptr<const RasterSnapshot> &raster = mask.asset.raster;
LayerRenderer::drawBrushPreview(raster ? QImage() : mask.asset.image(), placed, center(placed.center()), context, {.scale = scale},
{.patches = stroke->patches(), .pixelWidth = stroke->width, .pixelHeight = stroke->height,
.paintingMask = false, .sourceRect = stroke->sourceRect, .raster = raster});
return;
}
// Where a transform drag shows it, as the composite.
const LayerTransform placed = m_session.displayedMaskPlacement(layer).value_or(m_session.displayedTransform(layer));
LayerRenderer::draw(mask.asset.image(), placed, center(placed.center()), context, {.scale = scale});
}
// The folder's live mask, multiplied into the coverage.
FolderMaskClip::Applier CanvasView::liveFolderMaskClip(const BrushStroke &edit, double scale, const Center &center) const
{
return [&edit, scale, center](const QPainter &painter, QImage &coverage) {
QImage live(coverage.size(), QImage::Format_Grayscale8);
if (live.isNull())
throw ExportError(ExportError::Kind::render);
// Outside the mask's bounds stays hidden, as when committed.
live.fill(0);
LayerTransform transform = edit.paintTransform;
transform.sampling = LayerSampling::nearest;
const std::optional<ImportedImage> &base = edit.layer.mask ? std::optional(edit.layer.mask->asset) : std::nullopt;
{
QPainter drawing(&live);
drawing.setTransform(painter.deviceTransform());
// Swift's displayImage: halved near the size drawn.
const double device = LayerRenderer::deviceScale(drawing);
const auto shown = [device](const QImage &image, double width) {
return DownsampleCache::shared().imageDrawnAt(image, width * device / std::max(1, image.width()));
};
const std::shared_ptr<const RasterSnapshot> raster = base ? base->raster : nullptr;
const QImage image = base && !raster ? shown(base->image(), transform.size.width() * scale) : QImage();
const QImage rasterBase = raster && !raster->base.isNull()
? shown(raster->base, transform.size.width() * scale * raster->baseRect.width() / std::max(1, raster->width))
: QImage();
LayerRenderer::drawBrushPreview(image, transform, center(transform.center()), drawing, {.scale = scale},
{.patches = edit.patches(), .pixelWidth = edit.width, .pixelHeight = edit.height, .paintingMask = false,
.sourceRect = edit.sourceRect, .raster = raster, .rasterBase = rasterBase});
}
QPainter multiplying(&coverage);
if (!multiplying.isActive())
throw ExportError(ExportError::Kind::render);
multiplying.setCompositionMode(QPainter::CompositionMode_DestinationIn);
multiplying.drawImage(QRectF(coverage.rect()), BrushRaster::alphaView(live));
};
}
-37
View File
@@ -261,43 +261,6 @@ void CanvasView::draw(QPainter &context, const QRectF &dirty)
context.restore();
}
// The folder's live mask, multiplied into the coverage.
FolderMaskClip::Applier CanvasView::liveFolderMaskClip(const BrushStroke &edit, double scale, const Center &center) const
{
return [&edit, scale, center](const QPainter &painter, QImage &coverage) {
QImage live(coverage.size(), QImage::Format_Grayscale8);
if (live.isNull())
throw ExportError(ExportError::Kind::render);
// Outside the mask's bounds stays hidden, as when committed.
live.fill(0);
LayerTransform transform = edit.paintTransform;
transform.sampling = LayerSampling::nearest;
const std::optional<ImportedImage> &base = edit.layer.mask ? std::optional(edit.layer.mask->asset) : std::nullopt;
{
QPainter drawing(&live);
drawing.setTransform(painter.deviceTransform());
// Swift's displayImage: halved near the size drawn.
const double device = LayerRenderer::deviceScale(drawing);
const auto shown = [device](const QImage &image, double width) {
return DownsampleCache::shared().imageDrawnAt(image, width * device / std::max(1, image.width()));
};
const std::shared_ptr<const RasterSnapshot> raster = base ? base->raster : nullptr;
const QImage image = base && !raster ? shown(base->image(), transform.size.width() * scale) : QImage();
const QImage rasterBase = raster && !raster->base.isNull()
? shown(raster->base, transform.size.width() * scale * raster->baseRect.width() / std::max(1, raster->width))
: QImage();
LayerRenderer::drawBrushPreview(image, transform, center(transform.center()), drawing, {.scale = scale},
{.patches = edit.patches(), .pixelWidth = edit.width, .pixelHeight = edit.height, .paintingMask = false,
.sourceRect = edit.sourceRect, .raster = raster, .rasterBase = rasterBase});
}
QPainter multiplying(&coverage);
if (!multiplying.isActive())
throw ExportError(ExportError::Kind::render);
multiplying.setCompositionMode(QPainter::CompositionMode_DestinationIn);
multiplying.drawImage(QRectF(coverage.rect()), BrushRaster::alphaView(live));
};
}
void CanvasView::drawLayers(const CanvasDocument &document, double scale, const Center &center, QPainter &context)
{
if (const std::optional<ImageLayer> alone = m_session.maskAloneLayer()) {