New option for Toonz Raster Brush Tool : Draw Order - Palette Order (#1849)

* style order option for toonz raster brush

* change text to "draw order"
This commit is contained in:
shun-iwasawa 2018-03-14 17:33:59 +09:00 committed by masafumi-inoue
parent 133733bb6c
commit 975eb1fa6f
7 changed files with 150 additions and 58 deletions

View file

@ -4,6 +4,7 @@
#include "ttilesaver.h" #include "ttilesaver.h"
#include "tstopwatch.h" #include "tstopwatch.h"
#include <fstream> #include <fstream>
#include <QSet>
#undef DVAPI #undef DVAPI
#undef DVVAR #undef DVVAR
#ifdef TOONZLIB_EXPORTS #ifdef TOONZLIB_EXPORTS
@ -34,6 +35,9 @@ class DVAPI RasterStrokeGenerator {
int m_selectedStyle; int m_selectedStyle;
bool m_keepAntiAlias; bool m_keepAntiAlias;
bool m_doAnArc; bool m_doAnArc;
bool m_isPaletteOrder; // Used in the Draw Order option of Brush Tool,
// use style order to define line stacking order
QSet<int> m_aboveStyleIds;
// Ricalcola i punti in un nuovo sistema di riferimento // Ricalcola i punti in un nuovo sistema di riferimento
void translatePoints(std::vector<TThickPoint> &points, void translatePoints(std::vector<TThickPoint> &points,
@ -46,13 +50,17 @@ class DVAPI RasterStrokeGenerator {
public: public:
RasterStrokeGenerator(const TRasterCM32P &raster, Tasks task, RasterStrokeGenerator(const TRasterCM32P &raster, Tasks task,
ColorType colorType, int styleId, const TThickPoint &p, ColorType colorType, int styleId, const TThickPoint &p,
bool selective, int selectedStyle, bool keepAntialias); bool selective, int selectedStyle, bool keepAntialias,
bool isPaletteOrder = false);
~RasterStrokeGenerator(); ~RasterStrokeGenerator();
void setRaster(const TRasterCM32P &ras) { m_raster = ras; } void setRaster(const TRasterCM32P &ras) { m_raster = ras; }
void setStyle(int styleId) { m_styleId = styleId; } void setStyle(int styleId) { m_styleId = styleId; }
int getStyleId() const { return m_styleId; } int getStyleId() const { return m_styleId; }
bool isSelective() { return m_selective; } bool isSelective() { return m_selective; }
bool isPaletteOrder() { return m_isPaletteOrder; }
void setAboveStyleIds(QSet<int> &ids) { m_aboveStyleIds = ids; }
// Inserisce un punto in "m_points" // Inserisce un punto in "m_points"
bool add(const TThickPoint &p); bool add(const TThickPoint &p);

View file

@ -25,13 +25,13 @@ QImage rasterToQImage(const TRasterP &ras, bool premultiplied = false) {
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// drawOrderMode : 0=OverAll, 1=UnderAll, 2=PaletteOrder
void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId, void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId,
bool selective) { int drawOrderMode, const QSet<int> &aboveStyleIds) {
if (!out.getPointer() || !in.getPointer()) return; if (!out.getPointer() || !in.getPointer()) return;
assert(out->getSize() == in->getSize()); assert(out->getSize() == in->getSize());
int x, y; int x, y;
if (!selective) { if (drawOrderMode == 0) { // OverAll
for (y = 0; y < out->getLy(); y++) { for (y = 0; y < out->getLy(); y++) {
for (x = 0; x < out->getLx(); x++) { for (x = 0; x < out->getLx(); x++) {
#ifdef _DEBUG #ifdef _DEBUG
@ -44,16 +44,17 @@ void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId,
if (inPix->m == 0) continue; if (inPix->m == 0) continue;
TPixelCM32 *outPix = &out->pixels(y)[x]; TPixelCM32 *outPix = &out->pixels(y)[x];
bool sameStyleId = styleId == outPix->getInk(); bool sameStyleId = styleId == outPix->getInk();
// line with the same style : multiply tones
// line with different style : pick darker tone
int tone = sameStyleId ? outPix->getTone() * (255 - inPix->m) / 255 int tone = sameStyleId ? outPix->getTone() * (255 - inPix->m) / 255
: outPix->getTone(); : std::min(255 - inPix->m, outPix->getTone());
int ink = !sameStyleId && outPix->getTone() < 255 - inPix->m int ink = !sameStyleId && outPix->getTone() < 255 - inPix->m
? outPix->getInk() ? outPix->getInk()
: styleId; : styleId;
*outPix = *outPix = TPixelCM32(ink, outPix->getPaint(), tone);
TPixelCM32(ink, outPix->getPaint(), std::min(255 - inPix->m, tone));
} }
} }
} else { } else if (drawOrderMode == 1) { // UnderAll
for (y = 0; y < out->getLy(); y++) { for (y = 0; y < out->getLy(); y++) {
for (x = 0; x < out->getLx(); x++) { for (x = 0; x < out->getLx(); x++) {
#ifdef _DEBUG #ifdef _DEBUG
@ -66,14 +67,32 @@ void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId,
if (inPix->m == 0) continue; if (inPix->m == 0) continue;
TPixelCM32 *outPix = &out->pixels(y)[x]; TPixelCM32 *outPix = &out->pixels(y)[x];
bool sameStyleId = styleId == outPix->getInk(); bool sameStyleId = styleId == outPix->getInk();
// line with the same style : multiply tones
// line with different style : pick darker tone
int tone = sameStyleId ? outPix->getTone() * (255 - inPix->m) / 255 int tone = sameStyleId ? outPix->getTone() * (255 - inPix->m) / 255
: outPix->getTone(); : std::min(255 - inPix->m, outPix->getTone());
int ink = outPix->getTone() < 255 && !sameStyleId && int ink = !sameStyleId && outPix->getTone() <= 255 - inPix->m
outPix->getTone() <= 255 - inPix->m
? outPix->getInk() ? outPix->getInk()
: styleId; : styleId;
*outPix = *outPix = TPixelCM32(ink, outPix->getPaint(), tone);
TPixelCM32(ink, outPix->getPaint(), std::min(255 - inPix->m, tone)); }
}
} else { // PaletteOrder
for (y = 0; y < out->getLy(); y++) {
for (x = 0; x < out->getLx(); x++) {
TPixel32 *inPix = &in->pixels(y)[x];
if (inPix->m == 0) continue;
TPixelCM32 *outPix = &out->pixels(y)[x];
bool sameStyleId = styleId == outPix->getInk();
// line with the same style : multiply tones
// line with different style : pick darker tone
int tone = sameStyleId ? outPix->getTone() * (255 - inPix->m) / 255
: std::min(255 - inPix->m, outPix->getTone());
bool chooseOutPixInk = outPix->getTone() < 255 - inPix->m ||
(outPix->getTone() == 255 - inPix->m &&
aboveStyleIds.contains(outPix->getInk()));
int ink = !sameStyleId && chooseOutPixInk ? outPix->getInk() : styleId;
*outPix = TPixelCM32(ink, outPix->getPaint(), tone);
} }
} }
} }
@ -346,7 +365,7 @@ void BluredBrush::eraseDrawing(const TRasterP ras, const TRasterP rasBackup,
void BluredBrush::updateDrawing(const TRasterCM32P rasCM, void BluredBrush::updateDrawing(const TRasterCM32P rasCM,
const TRasterCM32P rasBackupCM, const TRasterCM32P rasBackupCM,
const TRect &bbox, int styleId, const TRect &bbox, int styleId,
bool selective) const { int drawOrderMode) const {
if (!rasCM) return; if (!rasCM) return;
TRect rasRect = rasCM->getBounds(); TRect rasRect = rasCM->getBounds();
@ -355,7 +374,7 @@ void BluredBrush::updateDrawing(const TRasterCM32P rasCM,
rasCM->copy(rasBackupCM->extract(targetRect), targetRect.getP00()); rasCM->copy(rasBackupCM->extract(targetRect), targetRect.getP00());
putOnRasterCM(rasCM->extract(targetRect), m_ras->extract(targetRect), styleId, putOnRasterCM(rasCM->extract(targetRect), m_ras->extract(targetRect), styleId,
selective); drawOrderMode, m_aboveStyleIds);
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------

View file

@ -8,6 +8,7 @@
#include "tcurves.h" #include "tcurves.h"
#include <QPainter> #include <QPainter>
#include <QImage> #include <QImage>
#include <QSet>
//======================================================= //=======================================================
// //
@ -24,6 +25,8 @@ class BluredBrush {
double m_oldOpacity; double m_oldOpacity;
bool m_enableDinamicOpacity; bool m_enableDinamicOpacity;
QSet<int> m_aboveStyleIds;
double getNextPadPosition(const TThickQuadratic &q, double t) const; double getNextPadPosition(const TThickQuadratic &q, double t) const;
public: public:
@ -37,11 +40,13 @@ public:
TRect getBoundFromPoints(const std::vector<TThickPoint> &points) const; TRect getBoundFromPoints(const std::vector<TThickPoint> &points) const;
// colormapped // colormapped
void updateDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM, void updateDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM,
const TRect &bbox, int styleId, bool selective) const; const TRect &bbox, int styleId, int drawOrderMode) const;
void eraseDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM, void eraseDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM,
const TRect &bbox, bool selective, int selectedStyleId, const TRect &bbox, bool selective, int selectedStyleId,
const std::wstring &mode) const; const std::wstring &mode) const;
void setAboveStyleIds(QSet<int> &ids) { m_aboveStyleIds = ids; }
// fullcolor // fullcolor
void updateDrawing(const TRasterP ras, const TRasterP rasBackup, void updateDrawing(const TRasterP ras, const TRasterP rasBackup,
const TPixel32 &color, const TRect &bbox, const TPixel32 &color, const TRect &bbox,

View file

@ -54,7 +54,7 @@ TEnv::DoubleVar RasterBrushMinSize("InknpaintRasterBrushMinSize", 1);
TEnv::DoubleVar RasterBrushMaxSize("InknpaintRasterBrushMaxSize", 5); TEnv::DoubleVar RasterBrushMaxSize("InknpaintRasterBrushMaxSize", 5);
TEnv::DoubleVar BrushAccuracy("InknpaintBrushAccuracy", 20); TEnv::DoubleVar BrushAccuracy("InknpaintBrushAccuracy", 20);
TEnv::DoubleVar BrushSmooth("InknpaintBrushSmooth", 0); TEnv::DoubleVar BrushSmooth("InknpaintBrushSmooth", 0);
TEnv::IntVar BrushSelective("InknpaintBrushSelective", 0); TEnv::IntVar BrushDrawOrder("InknpaintBrushDrawOrder", 0);
TEnv::IntVar BrushBreakSharpAngles("InknpaintBrushBreakSharpAngles", 0); TEnv::IntVar BrushBreakSharpAngles("InknpaintBrushBreakSharpAngles", 0);
TEnv::IntVar RasterBrushPencilMode("InknpaintRasterBrushPencilMode", 0); TEnv::IntVar RasterBrushPencilMode("InknpaintRasterBrushPencilMode", 0);
TEnv::IntVar BrushPressureSensitivity("InknpaintBrushPressureSensitivity", 1); TEnv::IntVar BrushPressureSensitivity("InknpaintBrushPressureSensitivity", 1);
@ -436,31 +436,56 @@ void addStrokeToImage(TTool::Application *application, const TVectorImageP &vi,
// getApplication()->getCurrentTool()->getTool()->notifyImageChanged(); // getApplication()->getCurrentTool()->getTool()->notifyImageChanged();
} }
//---------------------------------------------------------------------------------------------------------
enum DrawOrder { OverAll = 0, UnderAll, PaletteOrder };
void getAboveStyleIdSet(int styleId, TPaletteP palette,
QSet<int> &aboveStyles) {
if (!palette) return;
for (int p = 0; p < palette->getPageCount(); p++) {
TPalette::Page *page = palette->getPage(p);
for (int s = 0; s < page->getStyleCount(); s++) {
int tmpId = page->getStyleId(s);
if (tmpId == styleId) return;
if (tmpId != 0) aboveStyles.insert(tmpId);
}
}
}
//========================================================================================================= //=========================================================================================================
class RasterBrushUndo final : public TRasterUndo { class RasterBrushUndo final : public TRasterUndo {
std::vector<TThickPoint> m_points; std::vector<TThickPoint> m_points;
int m_styleId; int m_styleId;
bool m_selective; bool m_selective;
bool m_isPaletteOrder;
bool m_isPencil; bool m_isPencil;
public: public:
RasterBrushUndo(TTileSetCM32 *tileSet, const std::vector<TThickPoint> &points, RasterBrushUndo(TTileSetCM32 *tileSet, const std::vector<TThickPoint> &points,
int styleId, bool selective, TXshSimpleLevel *level, int styleId, bool selective, TXshSimpleLevel *level,
const TFrameId &frameId, bool isPencil, bool isFrameCreated, const TFrameId &frameId, bool isPencil, bool isFrameCreated,
bool isLevelCreated) bool isLevelCreated, bool isPaletteOrder)
: TRasterUndo(tileSet, level, frameId, isFrameCreated, isLevelCreated, 0) : TRasterUndo(tileSet, level, frameId, isFrameCreated, isLevelCreated, 0)
, m_points(points) , m_points(points)
, m_styleId(styleId) , m_styleId(styleId)
, m_selective(selective) , m_selective(selective)
, m_isPencil(isPencil) {} , m_isPencil(isPencil)
, m_isPaletteOrder(isPaletteOrder) {}
void redo() const override { void redo() const override {
insertLevelAndFrameIfNeeded(); insertLevelAndFrameIfNeeded();
TToonzImageP image = getImage(); TToonzImageP image = getImage();
TRasterCM32P ras = image->getRaster(); TRasterCM32P ras = image->getRaster();
RasterStrokeGenerator m_rasterTrack( RasterStrokeGenerator m_rasterTrack(ras, BRUSH, NONE, m_styleId,
ras, BRUSH, NONE, m_styleId, m_points[0], m_selective, 0, !m_isPencil); m_points[0], m_selective, 0,
!m_isPencil, m_isPaletteOrder);
if (m_isPaletteOrder) {
QSet<int> aboveStyleIds;
getAboveStyleIdSet(m_styleId, image->getPalette(), aboveStyleIds);
m_rasterTrack.setAboveStyleIds(aboveStyleIds);
}
m_rasterTrack.setPointsSequence(m_points); m_rasterTrack.setPointsSequence(m_points);
m_rasterTrack.generateStroke(m_isPencil); m_rasterTrack.generateStroke(m_isPencil);
image->setSavebox(image->getSavebox() + image->setSavebox(image->getSavebox() +
@ -482,20 +507,20 @@ public:
class RasterBluredBrushUndo final : public TRasterUndo { class RasterBluredBrushUndo final : public TRasterUndo {
std::vector<TThickPoint> m_points; std::vector<TThickPoint> m_points;
int m_styleId; int m_styleId;
bool m_selective; DrawOrder m_drawOrder;
int m_maxThick; int m_maxThick;
double m_hardness; double m_hardness;
public: public:
RasterBluredBrushUndo(TTileSetCM32 *tileSet, RasterBluredBrushUndo(TTileSetCM32 *tileSet,
const std::vector<TThickPoint> &points, int styleId, const std::vector<TThickPoint> &points, int styleId,
bool selective, TXshSimpleLevel *level, DrawOrder drawOrder, TXshSimpleLevel *level,
const TFrameId &frameId, int maxThick, double hardness, const TFrameId &frameId, int maxThick, double hardness,
bool isFrameCreated, bool isLevelCreated) bool isFrameCreated, bool isLevelCreated)
: TRasterUndo(tileSet, level, frameId, isFrameCreated, isLevelCreated, 0) : TRasterUndo(tileSet, level, frameId, isFrameCreated, isLevelCreated, 0)
, m_points(points) , m_points(points)
, m_styleId(styleId) , m_styleId(styleId)
, m_selective(selective) , m_drawOrder(drawOrder)
, m_maxThick(maxThick) , m_maxThick(maxThick)
, m_hardness(hardness) {} , m_hardness(hardness) {}
@ -510,11 +535,17 @@ public:
workRaster->clear(); workRaster->clear();
BluredBrush brush(workRaster, m_maxThick, brushPad, false); BluredBrush brush(workRaster, m_maxThick, brushPad, false);
if (m_drawOrder == PaletteOrder) {
QSet<int> aboveStyleIds;
getAboveStyleIdSet(m_styleId, image->getPalette(), aboveStyleIds);
brush.setAboveStyleIds(aboveStyleIds);
}
std::vector<TThickPoint> points; std::vector<TThickPoint> points;
points.push_back(m_points[0]); points.push_back(m_points[0]);
TRect bbox = brush.getBoundFromPoints(points); TRect bbox = brush.getBoundFromPoints(points);
brush.addPoint(m_points[0], 1); brush.addPoint(m_points[0], 1);
brush.updateDrawing(ras, ras, bbox, m_styleId, m_selective); brush.updateDrawing(ras, ras, bbox, m_styleId, (int)m_drawOrder);
if (m_points.size() > 1) { if (m_points.size() > 1) {
points.clear(); points.clear();
points.push_back(m_points[0]); points.push_back(m_points[0]);
@ -522,7 +553,7 @@ public:
bbox = brush.getBoundFromPoints(points); bbox = brush.getBoundFromPoints(points);
brush.addArc(m_points[0], (m_points[1] + m_points[0]) * 0.5, m_points[1], brush.addArc(m_points[0], (m_points[1] + m_points[0]) * 0.5, m_points[1],
1, 1); 1, 1);
brush.updateDrawing(ras, backupRas, bbox, m_styleId, m_selective); brush.updateDrawing(ras, backupRas, bbox, m_styleId, (int)m_drawOrder);
int i; int i;
for (i = 1; i + 2 < (int)m_points.size(); i = i + 2) { for (i = 1; i + 2 < (int)m_points.size(); i = i + 2) {
points.clear(); points.clear();
@ -531,7 +562,7 @@ public:
points.push_back(m_points[i + 2]); points.push_back(m_points[i + 2]);
bbox = brush.getBoundFromPoints(points); bbox = brush.getBoundFromPoints(points);
brush.addArc(m_points[i], m_points[i + 1], m_points[i + 2], 1, 1); brush.addArc(m_points[i], m_points[i + 1], m_points[i + 2], 1, 1);
brush.updateDrawing(ras, backupRas, bbox, m_styleId, m_selective); brush.updateDrawing(ras, backupRas, bbox, m_styleId, (int)m_drawOrder);
} }
} }
ToolUtils::updateSaveBox(); ToolUtils::updateSaveBox();
@ -768,7 +799,7 @@ BrushTool::BrushTool(std::string name, int targetType)
, m_smooth("Smooth:", 0, 50, 0) , m_smooth("Smooth:", 0, 50, 0)
, m_hardness("Hardness:", 0, 100, 100) , m_hardness("Hardness:", 0, 100, 100)
, m_preset("Preset:") , m_preset("Preset:")
, m_selective("Selective", false) , m_drawOrder("Draw Order:")
, m_breakAngles("Break", true) , m_breakAngles("Break", true)
, m_pencil("Pencil", false) , m_pencil("Pencil", false)
, m_pressure("Pressure", true) , m_pressure("Pressure", true)
@ -804,10 +835,14 @@ BrushTool::BrushTool(std::string name, int targetType)
m_prop[0].bind(m_rasThickness); m_prop[0].bind(m_rasThickness);
m_prop[0].bind(m_hardness); m_prop[0].bind(m_hardness);
m_prop[0].bind(m_smooth); m_prop[0].bind(m_smooth);
m_prop[0].bind(m_selective); m_prop[0].bind(m_drawOrder);
m_prop[0].bind(m_pencil); m_prop[0].bind(m_pencil);
m_pencil.setId("PencilMode"); m_pencil.setId("PencilMode");
m_selective.setId("Selective");
m_drawOrder.addValue(tr("Over All").toStdWString());
m_drawOrder.addValue(tr("Under All").toStdWString());
m_drawOrder.addValue(tr("Palette Order").toStdWString());
m_drawOrder.setId("DrawOrder");
} }
m_prop[0].bind(m_pressure); m_prop[0].bind(m_pressure);
@ -1013,7 +1048,7 @@ void BrushTool::updateTranslation() {
m_hardness.setQStringName(tr("Hardness:")); m_hardness.setQStringName(tr("Hardness:"));
m_accuracy.setQStringName(tr("Accuracy:")); m_accuracy.setQStringName(tr("Accuracy:"));
m_smooth.setQStringName(tr("Smooth:")); m_smooth.setQStringName(tr("Smooth:"));
m_selective.setQStringName(tr("Selective")); m_drawOrder.setQStringName(tr("Draw Order:"));
// m_filled.setQStringName(tr("Filled")); // m_filled.setQStringName(tr("Filled"));
m_preset.setQStringName(tr("Preset:")); m_preset.setQStringName(tr("Preset:"));
m_breakAngles.setQStringName(tr("Break")); m_breakAngles.setQStringName(tr("Break"));
@ -1064,7 +1099,7 @@ void BrushTool::onActivate() {
m_capStyle.setIndex(VectorCapStyle); m_capStyle.setIndex(VectorCapStyle);
m_joinStyle.setIndex(VectorJoinStyle); m_joinStyle.setIndex(VectorJoinStyle);
m_miterJoinLimit.setValue(VectorMiterValue); m_miterJoinLimit.setValue(VectorMiterValue);
m_selective.setValue(BrushSelective ? 1 : 0); if (m_targetType & TTool::ToonzImage) m_drawOrder.setIndex(BrushDrawOrder);
m_breakAngles.setValue(BrushBreakSharpAngles ? 1 : 0); m_breakAngles.setValue(BrushBreakSharpAngles ? 1 : 0);
m_pencil.setValue(RasterBrushPencilMode ? 1 : 0); m_pencil.setValue(RasterBrushPencilMode ? 1 : 0);
m_pressure.setValue(BrushPressureSensitivity ? 1 : 0); m_pressure.setValue(BrushPressureSensitivity ? 1 : 0);
@ -1188,6 +1223,15 @@ void BrushTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
TPointD halfThick(maxThick * 0.5, maxThick * 0.5); TPointD halfThick(maxThick * 0.5, maxThick * 0.5);
TRectD invalidateRect(pos - halfThick, pos + halfThick); TRectD invalidateRect(pos - halfThick, pos + halfThick);
// if the drawOrder mode = "Palette Order",
// get styleId list which is above the current style in the palette
DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex();
QSet<int> aboveStyleIds;
if (drawOrder == PaletteOrder) {
getAboveStyleIdSet(m_styleId, ri->getPalette(), aboveStyleIds);
}
if (m_hardness.getValue() == 100 || m_pencil.getValue()) { if (m_hardness.getValue() == 100 || m_pencil.getValue()) {
/*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる /*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる
* --*/ * --*/
@ -1195,8 +1239,12 @@ void BrushTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
TThickPoint thickPoint(pos + convert(ras->getCenter()), thickness); TThickPoint thickPoint(pos + convert(ras->getCenter()), thickness);
m_rasterTrack = new RasterStrokeGenerator( m_rasterTrack = new RasterStrokeGenerator(
ras, BRUSH, NONE, m_styleId, thickPoint, m_selective.getValue(), 0, ras, BRUSH, NONE, m_styleId, thickPoint, drawOrder != OverAll, 0,
!m_pencil.getValue()); !m_pencil.getValue(), drawOrder == PaletteOrder);
if (drawOrder == PaletteOrder)
m_rasterTrack->setAboveStyleIds(aboveStyleIds);
m_tileSaver->save(m_rasterTrack->getLastRect()); m_tileSaver->save(m_rasterTrack->getLastRect());
m_rasterTrack->generateLastPieceOfStroke(m_pencil.getValue()); m_rasterTrack->generateLastPieceOfStroke(m_pencil.getValue());
@ -1211,12 +1259,15 @@ void BrushTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
m_points.push_back(point); m_points.push_back(point);
m_bluredBrush = new BluredBrush(m_workRas, maxThick, m_brushPad, false); m_bluredBrush = new BluredBrush(m_workRas, maxThick, m_brushPad, false);
if (drawOrder == PaletteOrder)
m_bluredBrush->setAboveStyleIds(aboveStyleIds);
m_strokeRect = m_bluredBrush->getBoundFromPoints(m_points); m_strokeRect = m_bluredBrush->getBoundFromPoints(m_points);
updateWorkAndBackupRasters(m_strokeRect); updateWorkAndBackupRasters(m_strokeRect);
m_tileSaver->save(m_strokeRect); m_tileSaver->save(m_strokeRect);
m_bluredBrush->addPoint(point, 1); m_bluredBrush->addPoint(point, 1);
m_bluredBrush->updateDrawing(ri->getRaster(), m_backupRas, m_strokeRect, m_bluredBrush->updateDrawing(ri->getRaster(), m_backupRas, m_strokeRect,
m_styleId, m_selective.getValue()); m_styleId, drawOrder);
m_lastRect = m_strokeRect; m_lastRect = m_strokeRect;
m_smoothStroke.beginStroke(m_smooth.getValue()); m_smoothStroke.beginStroke(m_smooth.getValue());
@ -1356,7 +1407,7 @@ void BrushTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
} }
m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox, m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox,
m_styleId, m_selective.getValue()); m_styleId, m_drawOrder.getIndex());
m_strokeRect += bbox; m_strokeRect += bbox;
} }
} }
@ -1773,7 +1824,7 @@ void BrushTool::finishRasterBrush(const TPointD &pos, double pressureVal) {
m_tileSet, m_rasterTrack->getPointsSequence(), m_tileSet, m_rasterTrack->getPointsSequence(),
m_rasterTrack->getStyleId(), m_rasterTrack->isSelective(), m_rasterTrack->getStyleId(), m_rasterTrack->isSelective(),
simLevel.getPointer(), frameId, m_pencil.getValue(), m_isFrameCreated, simLevel.getPointer(), frameId, m_pencil.getValue(), m_isFrameCreated,
m_isLevelCreated)); m_isLevelCreated, m_rasterTrack->isPaletteOrder()));
} }
delete m_rasterTrack; delete m_rasterTrack;
m_rasterTrack = 0; m_rasterTrack = 0;
@ -1834,7 +1885,7 @@ void BrushTool::finishRasterBrush(const TPointD &pos, double pressureVal) {
} }
m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox, m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox,
m_styleId, m_selective.getValue()); m_styleId, m_drawOrder.getIndex());
m_strokeRect += bbox; m_strokeRect += bbox;
} }
if (pts.size() > 0) { if (pts.size() > 0) {
@ -1850,7 +1901,7 @@ void BrushTool::finishRasterBrush(const TPointD &pos, double pressureVal) {
m_tileSaver->save(bbox); m_tileSaver->save(bbox);
m_bluredBrush->addArc(points[0], points[1], points[2], 1, 1); m_bluredBrush->addArc(points[0], points[1], points[2], 1, 1);
m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox, m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox,
m_styleId, m_selective.getValue()); m_styleId, m_drawOrder.getIndex());
if (!rectUpdated) { if (!rectUpdated) {
invalidateRect = invalidateRect =
@ -1870,7 +1921,7 @@ void BrushTool::finishRasterBrush(const TPointD &pos, double pressureVal) {
if (m_tileSet->getTileCount() > 0) { if (m_tileSet->getTileCount() > 0) {
TUndoManager::manager()->add(new RasterBluredBrushUndo( TUndoManager::manager()->add(new RasterBluredBrushUndo(
m_tileSet, m_points, m_styleId, m_selective.getValue(), m_tileSet, m_points, m_styleId, (DrawOrder)m_drawOrder.getIndex(),
simLevel.getPointer(), frameId, m_rasThickness.getValue().second, simLevel.getPointer(), frameId, m_rasThickness.getValue().second,
m_hardness.getValue() * 0.01, m_isFrameCreated, m_isLevelCreated)); m_hardness.getValue() * 0.01, m_isFrameCreated, m_isLevelCreated));
} }
@ -2288,8 +2339,8 @@ bool BrushTool::onPropertyChanged(std::string propertyName) {
} else if (propertyName == m_preset.getName()) { } else if (propertyName == m_preset.getName()) {
loadPreset(); loadPreset();
notifyTool = true; notifyTool = true;
} else if (propertyName == m_selective.getName()) { } else if (propertyName == m_drawOrder.getName()) {
BrushSelective = m_selective.getValue(); BrushDrawOrder = m_drawOrder.getIndex();
} else if (propertyName == m_breakAngles.getName()) { } else if (propertyName == m_breakAngles.getName()) {
BrushBreakSharpAngles = m_breakAngles.getValue(); BrushBreakSharpAngles = m_breakAngles.getValue();
} else if (propertyName == m_pencil.getName()) { } else if (propertyName == m_pencil.getName()) {
@ -2402,7 +2453,7 @@ void BrushTool::loadPreset() {
ToolUtils::getBrushPad(preset.m_max, preset.m_hardness * 0.01); ToolUtils::getBrushPad(preset.m_max, preset.m_hardness * 0.01);
m_smooth.setValue(preset.m_smooth, true); m_smooth.setValue(preset.m_smooth, true);
m_hardness.setValue(preset.m_hardness, true); m_hardness.setValue(preset.m_hardness, true);
m_selective.setValue(preset.m_selective); m_drawOrder.setIndex(preset.m_drawOrder);
m_pencil.setValue(preset.m_pencil); m_pencil.setValue(preset.m_pencil);
m_pressure.setValue(preset.m_pressure); m_pressure.setValue(preset.m_pressure);
} }
@ -2427,7 +2478,7 @@ void BrushTool::addPreset(QString name) {
preset.m_acc = m_accuracy.getValue(); preset.m_acc = m_accuracy.getValue();
preset.m_smooth = m_smooth.getValue(); preset.m_smooth = m_smooth.getValue();
preset.m_hardness = m_hardness.getValue(); preset.m_hardness = m_hardness.getValue();
preset.m_selective = m_selective.getValue(); preset.m_drawOrder = m_drawOrder.getIndex();
preset.m_pencil = m_pencil.getValue(); preset.m_pencil = m_pencil.getValue();
preset.m_breakAngles = m_breakAngles.getValue(); preset.m_breakAngles = m_breakAngles.getValue();
preset.m_pressure = m_pressure.getValue(); preset.m_pressure = m_pressure.getValue();
@ -2485,7 +2536,7 @@ BrushData::BrushData()
, m_hardness(0.0) , m_hardness(0.0)
, m_opacityMin(0.0) , m_opacityMin(0.0)
, m_opacityMax(0.0) , m_opacityMax(0.0)
, m_selective(false) , m_drawOrder(0)
, m_pencil(false) , m_pencil(false)
, m_breakAngles(false) , m_breakAngles(false)
, m_pressure(false) , m_pressure(false)
@ -2508,7 +2559,7 @@ BrushData::BrushData(const std::wstring &name)
, m_hardness(0.0) , m_hardness(0.0)
, m_opacityMin(0.0) , m_opacityMin(0.0)
, m_opacityMax(0.0) , m_opacityMax(0.0)
, m_selective(false) , m_drawOrder(0)
, m_pencil(false) , m_pencil(false)
, m_breakAngles(false) , m_breakAngles(false)
, m_pressure(false) , m_pressure(false)
@ -2541,8 +2592,8 @@ void BrushData::saveData(TOStream &os) {
os.openChild("Opacity"); os.openChild("Opacity");
os << m_opacityMin << m_opacityMax; os << m_opacityMin << m_opacityMax;
os.closeChild(); os.closeChild();
os.openChild("Selective"); os.openChild("Draw_Order");
os << (int)m_selective; os << m_drawOrder;
os.closeChild(); os.closeChild();
os.openChild("Pencil"); os.openChild("Pencil");
os << (int)m_pencil; os << (int)m_pencil;
@ -2595,8 +2646,10 @@ void BrushData::loadData(TIStream &is) {
is >> m_hardness, is.matchEndTag(); is >> m_hardness, is.matchEndTag();
else if (tagName == "Opacity") else if (tagName == "Opacity")
is >> m_opacityMin >> m_opacityMax, is.matchEndTag(); is >> m_opacityMin >> m_opacityMax, is.matchEndTag();
else if (tagName == "Selective") else if (tagName == "Selective" ||
is >> val, m_selective = val, is.matchEndTag(); tagName == "Draw_Order") // "Selective" is left to keep backward
// compatibility
is >> m_drawOrder, is.matchEndTag();
else if (tagName == "Pencil") else if (tagName == "Pencil")
is >> val, m_pencil = val, is.matchEndTag(); is >> val, m_pencil = val, is.matchEndTag();
else if (tagName == "Break_Sharp_Angles") else if (tagName == "Break_Sharp_Angles")

View file

@ -39,8 +39,8 @@ struct BrushData final : public TPersist {
std::wstring m_name; std::wstring m_name;
double m_min, m_max, m_acc, m_smooth, m_hardness, m_opacityMin, m_opacityMax; double m_min, m_max, m_acc, m_smooth, m_hardness, m_opacityMin, m_opacityMax;
bool m_selective, m_pencil, m_breakAngles, m_pressure; bool m_pencil, m_breakAngles, m_pressure;
int m_cap, m_join, m_miter; int m_cap, m_join, m_miter, m_drawOrder;
double m_modifierSize, m_modifierOpacity; double m_modifierSize, m_modifierOpacity;
bool m_modifierEraser, m_modifierLockAlpha; bool m_modifierEraser, m_modifierLockAlpha;
@ -174,7 +174,7 @@ protected:
TDoubleProperty m_smooth; TDoubleProperty m_smooth;
TDoubleProperty m_hardness; TDoubleProperty m_hardness;
TEnumProperty m_preset; TEnumProperty m_preset;
TBoolProperty m_selective; TEnumProperty m_drawOrder;
TBoolProperty m_breakAngles; TBoolProperty m_breakAngles;
TBoolProperty m_pencil; TBoolProperty m_pencil;
TBoolProperty m_pressure; TBoolProperty m_pressure;

View file

@ -1625,7 +1625,8 @@ void MainWindow::defineActions() {
QAction *newToonzRasterLevelAction = createMenuFileAction( QAction *newToonzRasterLevelAction = createMenuFileAction(
MI_NewToonzRasterLevel, tr("&New Toonz Raster Level"), ""); MI_NewToonzRasterLevel, tr("&New Toonz Raster Level"), "");
newToonzRasterLevelAction->setIconText(tr("New Toonz Raster Level")); newToonzRasterLevelAction->setIconText(tr("New Toonz Raster Level"));
newToonzRasterLevelAction->setIcon(QIcon(":Resources/new_toonz_raster_level.svg")); newToonzRasterLevelAction->setIcon(
QIcon(":Resources/new_toonz_raster_level.svg"));
QAction *newRasterLevelAction = QAction *newRasterLevelAction =
createMenuFileAction(MI_NewRasterLevel, tr("&New Raster Level"), ""); createMenuFileAction(MI_NewRasterLevel, tr("&New Raster Level"), "");
newRasterLevelAction->setIconText(tr("New Raster Level")); newRasterLevelAction->setIconText(tr("New Raster Level"));
@ -2213,6 +2214,8 @@ void MainWindow::defineActions() {
tr("Pressure Sensitivity"), "Shift+P"); tr("Pressure Sensitivity"), "Shift+P");
createToolOptionsAction("A_ToolOption_SegmentInk", tr("Segment Ink"), "F8"); createToolOptionsAction("A_ToolOption_SegmentInk", tr("Segment Ink"), "F8");
createToolOptionsAction("A_ToolOption_Selective", tr("Selective"), "F7"); createToolOptionsAction("A_ToolOption_Selective", tr("Selective"), "F7");
createToolOptionsAction("A_ToolOption_DrawOrder",
tr("Brush Tool - Draw Order"), "");
createToolOptionsAction("A_ToolOption_Smooth", tr("Smooth"), ""); createToolOptionsAction("A_ToolOption_Smooth", tr("Smooth"), "");
createToolOptionsAction("A_ToolOption_Snap", tr("Snap"), ""); createToolOptionsAction("A_ToolOption_Snap", tr("Snap"), "");
createToolOptionsAction("A_ToolOption_AutoSelectDrawing", createToolOptionsAction("A_ToolOption_AutoSelectDrawing",

View file

@ -9,7 +9,8 @@ RasterStrokeGenerator::RasterStrokeGenerator(const TRasterCM32P &raster,
Tasks task, ColorType colorType, Tasks task, ColorType colorType,
int styleId, const TThickPoint &p, int styleId, const TThickPoint &p,
bool selective, int selectedStyle, bool selective, int selectedStyle,
bool keepAntialias) bool keepAntialias,
bool isPaletteOrder)
: m_raster(raster) : m_raster(raster)
, m_boxOfRaster(TRect(raster->getSize())) , m_boxOfRaster(TRect(raster->getSize()))
, m_styleId(styleId) , m_styleId(styleId)
@ -19,7 +20,8 @@ RasterStrokeGenerator::RasterStrokeGenerator(const TRasterCM32P &raster,
, m_eraseStyle(4095) , m_eraseStyle(4095)
, m_selectedStyle(selectedStyle) , m_selectedStyle(selectedStyle)
, m_keepAntiAlias(keepAntialias) , m_keepAntiAlias(keepAntialias)
, m_doAnArc(false) { , m_doAnArc(false)
, m_isPaletteOrder(isPaletteOrder) {
TThickPoint pp = p; TThickPoint pp = p;
m_points.push_back(pp); m_points.push_back(pp);
if (task == ERASE) m_styleId = m_eraseStyle; if (task == ERASE) m_styleId = m_eraseStyle;
@ -192,8 +194,10 @@ void RasterStrokeGenerator::placeOver(const TRasterCM32P &out,
continue; continue;
} }
if (outPix->isPureInk() && m_selective) { if (outPix->isPureInk() && m_selective) {
*outPix = TPixelCM32(outPix->getInk(), outPix->getPaint(), outTone); if (!m_isPaletteOrder || m_aboveStyleIds.contains(outPix->getInk())) {
continue; *outPix = TPixelCM32(outPix->getInk(), outPix->getPaint(), outTone);
continue;
}
} }
if (inTone <= outTone) { if (inTone <= outTone) {
*outPix = TPixelCM32(inPix->getInk(), outPix->getPaint(), inTone); *outPix = TPixelCM32(inPix->getInk(), outPix->getPaint(), inTone);