| |
| #include <algorithm> |
| |
| #include "mypainttoonzbrush.h" |
| #include "tropcm.h" |
| #include "tpixelutils.h" |
| #include <toonz/mypainthelpers.hpp> |
| |
| #include <QColor> |
| |
| namespace { |
| void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId, |
| bool lockAlpha) { |
| if (!out.getPointer() || !in.getPointer()) return; |
| assert(out->getSize() == in->getSize()); |
| int x, y; |
| for (y = 0; y < out->getLy(); y++) { |
| for (x = 0; x < out->getLx(); x++) { |
| #ifdef _DEBUG |
| assert(x >= 0 && x < in->getLx()); |
| assert(y >= 0 && y < in->getLy()); |
| assert(x >= 0 && x < out->getLx()); |
| assert(y >= 0 && y < out->getLy()); |
| #endif |
| TPixel32 *inPix = &in->pixels(y)[x]; |
| if (inPix->m == 0) continue; |
| TPixelCM32 *outPix = &out->pixels(y)[x]; |
| if (lockAlpha && !outPix->isPureInk() && outPix->getPaint() == 0 && |
| outPix->getTone() == 255) { |
| *outPix = |
| TPixelCM32(outPix->getInk(), outPix->getPaint(), outPix->getTone()); |
| continue; |
| } |
| bool sameStyleId = styleId == outPix->getInk(); |
| |
| |
| |
| int tone = lockAlpha ? outPix->getTone() |
| : sameStyleId ? outPix->getTone() * (255 - inPix->m) / 255 |
| : std::min(255 - inPix->m, outPix->getTone()); |
| int ink = !sameStyleId && outPix->getTone() < 255 - inPix->m |
| ? outPix->getInk() |
| : styleId; |
| *outPix = TPixelCM32(ink, outPix->getPaint(), tone); |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| class Raster32PMyPaintSurface::Internal |
| : public mypaint::helpers::SurfaceCustom<readPixel, writePixel, askRead, |
| askWrite> { |
| public: |
| typedef SurfaceCustom Parent; |
| Internal(Raster32PMyPaintSurface &owner) |
| : SurfaceCustom(owner.m_ras->pixels(), owner.m_ras->getLx(), |
| owner.m_ras->getLy(), owner.m_ras->getPixelSize(), |
| owner.m_ras->getRowSize(), &owner) {} |
| }; |
| |
| |
| |
| |
| |
| |
| |
| Raster32PMyPaintSurface::Raster32PMyPaintSurface(const TRaster32P &ras) |
| : m_ras(ras), controller(), internal() { |
| assert(ras); |
| internal = new Internal(*this); |
| } |
| |
| Raster32PMyPaintSurface::Raster32PMyPaintSurface(const TRaster32P &ras, |
| RasterController &controller) |
| : m_ras(ras), controller(&controller), internal() { |
| assert(ras); |
| internal = new Internal(*this); |
| } |
| |
| Raster32PMyPaintSurface::~Raster32PMyPaintSurface() { delete internal; } |
| |
| bool Raster32PMyPaintSurface::getColor(float x, float y, float radius, |
| float &colorR, float &colorG, |
| float &colorB, float &colorA) { |
| return internal->getColor(x, y, radius, colorR, colorG, colorB, colorA); |
| } |
| |
| bool Raster32PMyPaintSurface::drawDab(const mypaint::Dab &dab) { |
| return internal->drawDab(dab); |
| } |
| |
| bool Raster32PMyPaintSurface::getAntialiasing() const { |
| return internal->antialiasing; |
| } |
| |
| void Raster32PMyPaintSurface::setAntialiasing(bool value) { |
| internal->antialiasing = value; |
| } |
| |
| |
| |
| |
| |
| |
| |
| MyPaintToonzBrush::MyPaintToonzBrush( |
| const TRaster32P &ras, |
| RasterController &controller, |
| const mypaint::Brush &brush, |
| bool interpolation |
| ) |
| : m_ras(ras) |
| , m_mypaintSurface(m_ras, controller) |
| , brush(brush) |
| , reset(true) |
| , interpolation(interpolation) |
| { |
| |
| float aa = this->brush.getBaseValue(MYPAINT_BRUSH_SETTING_ANTI_ALIASING); |
| m_mypaintSurface.setAntialiasing(aa > 0.5f); |
| |
| |
| this->brush.setBaseValue(MYPAINT_BRUSH_SETTING_ANTI_ALIASING, 0.f); |
| for (int i = 0; i < MYPAINT_BRUSH_INPUTS_COUNT; ++i) |
| this->brush.setMappingN(MYPAINT_BRUSH_SETTING_ANTI_ALIASING, |
| (MyPaintBrushInput)i, 0); |
| } |
| |
| void MyPaintToonzBrush::beginStroke() { |
| brush.reset(); |
| brush.newStroke(); |
| reset = true; |
| } |
| |
| void MyPaintToonzBrush::endStroke() { |
| if (!reset) { |
| if (interpolation) |
| strokeTo(TPointD(current.x, current.y), current.pressure, 0.f); |
| beginStroke(); |
| } |
| } |
| |
| void MyPaintToonzBrush::strokeTo(const TPointD &point, double pressure, |
| double dtime) { |
| Params next(point.x, point.y, pressure, 0.0); |
| |
| if (reset) { |
| current = next; |
| previous = current; |
| reset = false; |
| |
| brush.setState(MYPAINT_BRUSH_STATE_X, current.x); |
| brush.setState(MYPAINT_BRUSH_STATE_Y, current.y); |
| brush.setState(MYPAINT_BRUSH_STATE_ACTUAL_X, current.x); |
| brush.setState(MYPAINT_BRUSH_STATE_ACTUAL_Y, current.y); |
| return; |
| } |
| |
| if (interpolation) { |
| next.time = current.time + dtime; |
| |
| |
| const double threshold = 1.0; |
| const double thresholdSqr = threshold * threshold; |
| const int maxLevel = 16; |
| |
| |
| Segment stack[maxLevel + 1]; |
| Params p0; |
| Segment *segment = stack; |
| Segment *maxSegment = segment + maxLevel; |
| p0.setMedian(previous, current); |
| segment->p1 = current; |
| segment->p2.setMedian(current, next); |
| |
| |
| while (true) { |
| double dx = segment->p2.x - p0.x; |
| double dy = segment->p2.y - p0.y; |
| if (dx * dx + dy * dy > thresholdSqr && segment != maxSegment) { |
| Segment *sub = segment + 1; |
| sub->p1.setMedian(p0, segment->p1); |
| segment->p1.setMedian(segment->p1, segment->p2); |
| sub->p2.setMedian(sub->p1, segment->p1); |
| segment = sub; |
| } else { |
| brush.strokeTo(m_mypaintSurface, segment->p2.x, segment->p2.y, |
| segment->p2.pressure, 0.f, 0.f, |
| segment->p2.time - p0.time); |
| if (segment == stack) break; |
| p0 = segment->p2; |
| --segment; |
| } |
| } |
| |
| |
| previous = current; |
| current = next; |
| |
| |
| previous.time = 0.0; |
| current.time = dtime; |
| } else { |
| brush.strokeTo(m_mypaintSurface, point.x, point.y, pressure, 0.f, 0.f, dtime); |
| } |
| } |
| |
| |
| |
| void MyPaintToonzBrush::updateDrawing(const TRasterCM32P rasCM, |
| const TRasterCM32P rasBackupCM, |
| const TRect &bbox, int styleId, |
| bool lockAlpha) const { |
| if (!rasCM) return; |
| |
| TRect rasRect = rasCM->getBounds(); |
| TRect targetRect = bbox * rasRect; |
| if (targetRect.isEmpty()) return; |
| |
| rasCM->copy(rasBackupCM->extract(targetRect), targetRect.getP00()); |
| putOnRasterCM(rasCM->extract(targetRect), m_ras->extract(targetRect), styleId, |
| lockAlpha); |
| } |